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


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,这是可为空的属性。

Answers:


20

由于PHP 7.4为属性引入了类型提示,因此特别重要的是为所有属性提供有效值,以便所有属性都具有与其声明的类型匹配的值。

从未赋值的变量没有null值,但undefined处于状态,永远不会与任何声明的type匹配undefined !== null

对于上面的代码,如果您这样做:

$f = new Foo(1);
$f->getVal();

您将获得:

致命错误:未捕获错误:初始化之前不得访问类型为Foo :: $ val的属性

因为$val既不是也不stringnull在访问它时。

解决此问题的方法是将值分配给与声明的类型匹配的所有属性。您可以将其作为属性的默认值,也可以在构造期间执行此操作,具体取决于您的偏好和属性的类型。

例如,对于上述情况,您可以执行以下操作:

class Foo {

    private int $id;
    private ?string $val = null; // <-- declaring default null value for the property
    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();
    }

现在,所有属性将具有有效值,并且实例将处于有效状态。

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

对于自动生成的ID,建议的前进方法是将类型声明更改为?int $id = null。对于其他所有内容,只需为属性的类型选择一个适当的值。


-5

我的错误:

"Typed property Proxies\\__CG__\\App\\Entity\\Organization::$ must not be accessed before initialization (in __sleep)"

我的解决方案-在该类中添加下一个方法:

public function __sleep()
{
    return [];
}

1
请准确阅读问题,然后根据问题回答,而不完全根据您的问题/解决方案。
MAChitgarha
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.