Почему я внезапно получаю сообщение об ошибке «Свойство Typed не должно быть доступно до инициализации» при введении подсказок типа свойств?

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, которые могут иметь значение null.

yivi
источник

Ответы:

21

Поскольку в 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();
    }

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

Это может случиться особенно часто, когда вы полагаетесь на значения, которые поступают из БД для значений сущностей. Например, автоматически сгенерированные идентификаторы или создание и / или обновление значений; которые часто остаются в качестве концерна БД.

Для автоматически сгенерированных идентификаторов рекомендуемый способ продвижения вперед - изменить объявление типа на ?int $id = null. Для всего остального просто выберите соответствующее значение для типа свойства.

yivi
источник
-5

Моя ошибка:

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

Мое решение - добавить следующий метод в класс:

public function __sleep()
{
    return [];
}
Lebnik
источник
1
Пожалуйста, внимательно прочитайте вопрос, затем ответьте на основе вопроса, а не на основе вашей проблемы / решения.
MAChitgarha