为啥我在引入属性类型提示时突然收到“在初始化之前不能访问类型属性”错误?
Posted
技术标签:
【中文标题】为啥我在引入属性类型提示时突然收到“在初始化之前不能访问类型属性”错误?【英文标题】:Why I am suddenly getting a "Typed property must not be accessed before initialization" error when introducing properties type hints?为什么我在引入属性类型提示时突然收到“在初始化之前不能访问类型属性”错误? 【发布时间】:2020-04-03 13:04:55 【问题描述】:我已经更新了我的类定义以利用新引入的属性类型提示,如下所示:
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 上保存我的实体时,我收到一条错误消息:
在初始化之前不能访问类型化的属性
这不仅发生在$id
或$createdAt
上,还发生在$value
或$updatedAt
上,它们都是可为空的属性。
【问题讨论】:
【参考方案1】:由于 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();
现在所有属性都将具有 valid 值,并且实例将处于有效状态。
当您依赖来自数据库的值来获取实体值时,这种情况尤其常见。例如。自动生成的 ID,或创建和/或更新的值;这通常是一个数据库问题。
对于自动生成的 ID,the recommended way forward 是将类型声明更改为:
private ?int $id = null
剩下的,只需为属性类型选择一个合适的值。
【讨论】:
换句话说,从 PHP 7.4 开始,类型提示的类成员存在 null 安全性。【参考方案2】:对于可为空的类型属性,您需要使用语法
private ?string $val = null;
否则会引发致命错误。
由于这个概念会导致不必要的致命错误,我创建了一个错误报告https://bugs.php.net/bug.php?id=79620 - 没有成功,但至少我尝试过...
【讨论】:
a)其他答案已经涵盖了这一点。 b) 这不是错误。这是(好的)设计。如果一个属性除了定义的类型之外还可能包含null
,那么您需要明确说明它。我希望这样的报告会被立即拒绝。以上是关于为啥我在引入属性类型提示时突然收到“在初始化之前不能访问类型属性”错误?的主要内容,如果未能解决你的问题,请参考以下文章
为啥我会收到此错误:未捕获的类型错误:无法读取 null 的属性 'classList'
为啥我在从 Java 批量执行 PostgreSQL 存储过程时收到错误消息,提示“未预期结果”?
为啥我在发送 SMTP 电子邮件时收到“'property cannot be assigned”?
为啥我在发送 SMTP 电子邮件时收到“'property cannot be assigned”?