为什么我在引入属性类型提示时,突然得到一个"类型属性在初始化前不得访问"的错误?
回答 2
浏览 12.4万
2019-12-10
我已经更新了我的类定义,以利用新引入的属性类型提示,就像这样。
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
上,它们都是可忽略不计的属性。
2 个回答
#1楼
已采纳
得票数 191
由于 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值,并且实例将处于有效的状态。
当你依赖来自DB的实体值时,这种情况会特别多。例如,自动生成的ID,或创建和/或更新的值;这些值通常被留作DB关注。
对于自动生成的ID,推荐的前进方式是将类型声明改为。
private ?int $id = null
其余的,只需为属性的类型选择一个适当的值即可。
换句话说,从PHP7.4开始,类型提示的类成员就有了空的安全。
- James Bond 2020-10-23
如果需要的话,你也可以使用isset()来检查属性是否被安全初始化,以避免初始化,例如用null来初始化。
- Max 2022-06-22
#2楼
得票数 32
对于可归零类型的属性,你需要使用语法
private ?string $val = null;
否则它就会抛出一个致命的错误。
由于这个概念导致了不必要的致命错误,我已经创建了一个错误报告https://bugs.php.net/bug.php?id=79620 - 没有成功,但至少我尝试了...
a) 这在另一个答案中已经涉及。 b) 这不是一个错误。那是(好的)设计。如果一个属性除了定义的类型外还可能持有
null
,你要明确说明这一点。我希望这样的报告会被立即拒绝。
- yivi 2020-05-22