我已经更新了我的类定义以利用新引入的属性类型提示,如下所示:
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; }
}
但是当试图在教义上拯救我的实体时,我收到一个错误说:
初始化前不得访问类型化属性
这不仅发生在$id
或$createdAt
上,也发生在$value
或$updatedAt
上,它们是可为空的属性。
由于 PHP 7.4 引入了属性的类型提示,因此为所有属性提供有效值尤为重要,以便所有属性都具有与其声明类型匹配的值。
从未分配过的属性没有null
值,但它处于undefined
状态,永远不会与任何声明的类型匹配。undefined !== null
.
对于上面的代码,如果您这样做了:
$f = new Foo(1);
$f->getVal();
你会得到:
致命错误:未捕获错误:初始化之前不得访问类型化属性 Foo::$val
由于$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,或创建和/或更新的值; 通常作为数据库关注的问题。
对于自动生成的 ID,建议的方法是将类型声明更改为:
private ?int $id = null
对于所有其他内容,只需为属性的类型选择适当的值。
对于可为空的类型化属性,您需要使用语法
private ?string $val = null;
否则会引发致命错误。
由于这个概念会导致不必要的致命错误,因此我 https://bugs.php.net/bug.php?id=79620 创建了一个错误报告 - 没有成功,但至少我尝试过......