为什么在引入属性类型提示时突然出现“类型化属性在初始化前不能访问”错误?

我已经更新了类定义,以使用新引入的属性类型提示,如下所示:

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; }
}

但是当我试图在信条上保存我的实体时,我得到了一个错误:

Typed property must not be accessed before initialization

这不仅发生在 $id$createdAt上,也发生在 $value$updatedAt上,它们是可为空的属性。

134407 次浏览

由于 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();
}

Now all properties would have a 有效 value and the the instance would be on a valid state.

当您依赖数据库中的值来获取实体值时,这种情况尤其常见。例如,自动生成的 ID,或者创建和/或更新的值; 这些通常作为数据库关注的问题。

For auto-generated IDs, the recommended way forward is to change the type declaration to:

private ?int $id = null

对于所有其他属性,只需为属性的类型选择一个适当的值。

For nullable typed properties you need to use syntax

private ?string $val = null;

否则将抛出致命错误。

由于这个概念会导致不必要的致命错误,我已经创建了一个错误报告 https://bugs.php.net/bug.php?id=79620-没有成功,但至少我尝试..。