为什么在引入属性类型提示时突然出现 "Typed property must not be accessed before initialization" 错误?
Why I am suddenly getting a "Typed property must not be accessed before initialization" error when introducing properties type hints?
我更新了 class 定义以使用新引入的 属性 类型提示,如下所示:
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 上保存我的实体时,我收到一条错误消息:
Typed property must not be accessed before initialization
这不仅发生在 $id
或 $createdAt
上,而且发生在 $value
或 $updatedAt
上,它们是可为 null 的属性。
自从 PHP7.4 引入了属性类型提示,为所有属性提供有效值就显得尤为重要,这样所有属性的值都与其声明的类型相匹配。
一个从未被赋值的 属性 没有 null
值,但它处于 undefined
状态, 永远不会匹配任何值声明类型。 undefined !== null
.
对于上面的代码,如果你这样做了:
$f = new Foo(1);
$f->getVal();
你会得到:
Fatal error: Uncaught Error: Typed property Foo::$val must not be accessed before initialization
因为 $val
在访问时既不是 string
也不是 null
。
解决这个问题的方法是为所有匹配声明类型的属性赋值。您可以将此作为 属性 的默认值或在构造期间执行此操作,具体取决于您的偏好和 属性.
的类型
例如,对于上面的一个可以这样做:
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();
}
现在所有属性都将具有 有效 值并且实例将处于有效状态。
当您依赖来自数据库的值作为实体值时,这种情况尤其常见。例如。自动生成的 ID,或创建 and/or 更新的值;这通常作为数据库问题留下。
对于自动生成的ID,the recommended way forward是将类型声明改为:
private ?int $id = null
对于所有其他内容,只需为 属性 的类型选择一个合适的值即可。
对于可为 null 的类型属性,您需要使用语法
private ?string $val = null;
否则会抛出致命错误。
由于这个概念会导致不必要的致命错误,我创建了一个错误报告 https://bugs.php.net/bug.php?id=79620 - 没有成功,但至少我试过了...
我更新了 class 定义以使用新引入的 属性 类型提示,如下所示:
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 上保存我的实体时,我收到一条错误消息:
Typed property must not be accessed before initialization
这不仅发生在 $id
或 $createdAt
上,而且发生在 $value
或 $updatedAt
上,它们是可为 null 的属性。
自从 PHP7.4 引入了属性类型提示,为所有属性提供有效值就显得尤为重要,这样所有属性的值都与其声明的类型相匹配。
一个从未被赋值的 属性 没有 null
值,但它处于 undefined
状态, 永远不会匹配任何值声明类型。 undefined !== null
.
对于上面的代码,如果你这样做了:
$f = new Foo(1);
$f->getVal();
你会得到:
Fatal error: Uncaught Error: Typed property Foo::$val must not be accessed before initialization
因为 $val
在访问时既不是 string
也不是 null
。
解决这个问题的方法是为所有匹配声明类型的属性赋值。您可以将此作为 属性 的默认值或在构造期间执行此操作,具体取决于您的偏好和 属性.
的类型例如,对于上面的一个可以这样做:
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();
}
现在所有属性都将具有 有效 值并且实例将处于有效状态。
当您依赖来自数据库的值作为实体值时,这种情况尤其常见。例如。自动生成的 ID,或创建 and/or 更新的值;这通常作为数据库问题留下。
对于自动生成的ID,the recommended way forward是将类型声明改为:
private ?int $id = null
对于所有其他内容,只需为 属性 的类型选择一个合适的值即可。
对于可为 null 的类型属性,您需要使用语法
private ?string $val = null;
否则会抛出致命错误。
由于这个概念会导致不必要的致命错误,我创建了一个错误报告 https://bugs.php.net/bug.php?id=79620 - 没有成功,但至少我试过了...