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

yiv*_*ivi 62 php type-hinting doctrine-orm php-7 php-7.4

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

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; }
}
Run Code Online (Sandbox Code Playgroud)

但是当试图在 Doctrine 上保存我的实体时,我收到一条错误消息:

在初始化之前不能访问类型化的属性

这不仅发生在$idor 上$createdAt,而且发生在$valueor 上$updatedAt,它们是可以为空的属性。

yiv*_*ivi 108

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

从未分配过的属性没有null值,但它处于一个undefined状态,永远不会匹配任何声明的 typeundefined !== null.

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

$f = new Foo(1);
$f->getVal();
Run Code Online (Sandbox Code Playgroud)

你会得到:

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

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

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

例如,对于上面的一个可以这样做:

$f = new Foo(1);
$f->getVal();
Run Code Online (Sandbox Code Playgroud)

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

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

对于自动生成的 ID,推荐的方法是将类型声明更改为:

private ?int $id = null
Run Code Online (Sandbox Code Playgroud)

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

  • 如果需要,您还可以使用 isset() 检查属性是否已安全初始化,以避免使用 null 等进行初始化 (4认同)
  • 换句话说,从 PHP 7.4 开始,类型提示的类成员就具有 **null 安全性**。 (3认同)

Hhy*_*ion 13

对于可为空类型的属性,您需要使用语法

private ?string $val = null;

否则会抛出致命错误。

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

  • a)其他答案已经涵盖了这一点。b) 这不是一个错误。这是(良好的)设计。如果一个属性除了定义的类型之外还可能包含“null”,那么您需要明确说明它。我预计这样的报告会立即被拒绝。 (9认同)