为什么我突然收到“在初始化之前不能访问类型化属性"?引入属性类型提示时出错?
我已经更新了我的类定义以使用新引入的属性类型提示,如下所示:
I have updated my class definitions to make use of the newly introduced property type hints, like this:
class Foo {
private int $id;
private ?string $val;
private DateTimeInterface $createdAt;
private ?DateTimeInterface $updatedAt;
public function __construct(int $id) {
$this->id = $id;
}
public function getId(): int { return $this->id; }
public function getVal(): ?string { return $this->val; }
public function getCreatedAt(): ?DateTimeInterface { return $this->createdAt; }
public function getUpdatedAt(): ?DateTimeInterface { return $this->updatedAt; }
public function setVal(?string $val) { $this->val = $val; }
public function setCreatedAt(DateTimeInterface $date) { $this->createdAt = $date; }
public function setUpdatedAt(DateTimeInterface $date) { $this->updatedAt = $date; }
}
但是当我尝试在 Doctrine 上保存我的实体时,我收到一条错误消息:
But when trying to save my entity on Doctrine I am getting an error saying:
在初始化之前不能访问类型化的属性
Typed property must not be accessed before initialization
这不仅发生在 $id
或 $createdAt
,而且发生在 $value
或 $updatedAt
>,它们是可为空的属性.
This not only happens with $id
or $createdAt
, but also happen with $value
or $updatedAt
, which are nullable properties.
推荐答案
由于 PHP 7.4 为属性引入了类型提示,因此为所有属性提供有效值尤为重要,以便所有属性都具有与其声明类型匹配的值.
Since PHP 7.4 introduces type-hinting for properties, it is particularly important to provide valid values for all properties, so that all properties have values that match their declared types.
从未赋值的属性没有 null
值,但它处于 undefined
状态,永远不会匹配任何声明的类型.undefined !== null
.
A property that has never been assigned doesn't have a null
value, but it is on an undefined
state, which will never match any declared type. undefined !== null
.
对于上面的代码,如果你这样做了:
For the code above, if you did:
$f = new Foo(1);
$f->getVal();
你会得到:
致命错误:未捕获错误:类型化属性 Foo::$val 不能在初始化前访问
Fatal error: Uncaught Error: Typed property Foo::$val must not be accessed before initialization
因为$val
在访问时既不是string
也不是null
.
Since $val
is neither string
nor null
when accessing it.
解决这个问题的方法是为所有与声明类型匹配的属性赋值.您可以将此作为属性的默认值或在构建期间执行此操作,具体取决于您的偏好和属性类型.
The way to get around this is to assign values to all your properties that match the declared types. You can do this either as default values for the property or during construction, depending on your preference and the type of the property.
例如,对于上面的一个可以这样做:
For example, for the above one could do:
class Foo {
private int $id;
private ?string $val = null; // <-- declaring default null value for the property
private Collection $collection;
private DateTimeInterface $createdAt;
private ?DateTimeInterface $updatedAt;
public function __construct(int $id) {
// and on the constructor we set the default values for all the other
// properties, so now the instance is on a valid state
$this->id = $id;
$this->createdAt = new DateTimeImmutable();
$this->updatedAt = new DateTimeImmutable();
$this->collection = new ArrayCollection();
}
现在所有属性都将具有 valid 值,并且实例将处于有效状态.
Now all properties would have a valid value and the the instance would be on a valid state.
当您依赖来自数据库的值作为实体值时,这种情况尤其常见.例如.自动生成的 ID,或创建和/或更新的值;这通常是数据库关注的问题.
This can hit particularly often when you are relying on values that come from the DB for entity values. E.g. auto-generated IDs, or creation and/or updated values; which often are left as a DB concern.
对于自动生成的 ID,推荐的前进方式是将类型声明更改为:
For auto-generated IDs, the recommended way forward is to change the type declaration to:
private ?int $id = null
对于其余的,只需为属性的类型选择一个合适的值即可.
For all the rest, just choose an appropriate value for the property's type.
相关文章