Чому я несподівано отримую помилку "Введене властивість не має доступу до ініціалізації" під час введення підказки типу властивостей?


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

Але при спробі зберегти мою сутність на Доктрині я отримую помилку:

Введене властивість не має доступу до ініціалізації

Це відбувається не тільки з $idабо $createdAt, але також трапляється з $valueабо $updatedAt, які є незмінними властивостями.

Відповіді:


20

Оскільки PHP 7.4 запроваджує натяк на тип для властивостей, особливо важливо надати дійсні значення для всіх властивостей, щоб усі властивості мали значення, що відповідають їх заявленим типам.

Змінна, яка ніколи не була призначена, не має nullзначення, але вона знаходиться в undefinedстані, яке ніколи не буде відповідати жодному оголошеному типу . undefined !== null.

Для наведеного вище коду, якщо ви зробили:

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

Ви отримаєте:

Фатальна помилка: Uncaught Помилка: Введене властивість 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();
    }

Тепер усі властивості мали б дійсне значення, а екземпляр знаходився б у дійсному стані.

Це може траплятися особливо часто, коли ви покладаєтесь на значення, що надходять із БД для значень сутності. Наприклад, автоматично згенеровані ідентифікатори, або створення та / або оновлені значення; які часто залишаються занепокоєнням БД.

Для автоматично згенерованих ідентифікаторів рекомендованим способом вперед є зміна декларації типу на ?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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.