プロパティタイプのヒントを導入すると、「初期化前に型付きプロパティにアクセスしてはならない」というエラーが突然表示されるのはなぜですか?


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で発生するだけでなく、null許容プロパティである$valueまたはでも発生し$updatedAtます。

回答:


20

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

これで、すべてのプロパティの値が有効になり、インスタンスは有効な状態になります。

これは、エンティティの値をDBから取得した値に依存している場合に特によく発生します。たとえば、自動生成されたID、または作成や更新された値。多くの場合、DBの問題として残されます。

自動生成された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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.