Задать вопрос
@AlexandrMa

Почему появляется Typed property must not be accessed before initialization?

Fatal error: Uncaught Error: Typed property Product::$parentId must not be accessed before initialization

class Product
{
  public int $id;
  public int $parentId;

  public function __construct(int $id)
  {
    $this->id = $id;
  }

  public function getParentId(): ?int
  {
    return $this->parentId;
  }

}

$obj = new Product(1);
if(!empty($obj->getParentId())){
  echo 'ok';
}

Странно, что даже проверка empty ругается.

public ?int $parentId = null;

Если указать в начале, то всё работает, как нужно. Но:

1. Разве по умолчанию свойства не null?
2. У меня 20-30 свойств. Для каждого что-ли делать так? Код какой-то не логичный и громоздкий.
  • Вопрос задан
  • 364 просмотра
Подписаться 1 Простой 1 комментарий
Решения вопроса 3
nokimaro
@nokimaro
Меня невозможно остановить, если я смогу начать.
Используйте Constructor property promotion чтобы писать меньше букв)
<?php

class Product
{
    public function __construct(
        public int $id,
        public ?int $parentId = null
    ) {
    }

    public function getParentId(): ?int
    {
        return $this->parentId;
    }

}

$obj = new Product(1);
if (!empty($obj->getParentId())) {
    echo 'ok';
}


Либо уберите типизацию у свойства и при public $parentId; ошибки не будет. Всё как и написано в тексте ошибки, нельзя обратиться к типизированному свойству до его инициализации, а значит нужно либо задать значение по умолчанию при описании свойства, либо через конструктор, либо вызвав setter.

uninitialized и typed properties
https://php.watch/versions/7.4/typed-properties#un...
Ответ написан
Комментировать
@Vitsliputsli
1. Разве по умолчанию свойства не null?
2. У меня 20-30 свойств. Для каждого что-ли делать так? Код какой-то не логичный и громоздкий.

1. Нет, в данном случае у свойства нет значения, оно не инициализировано. Какое значение вы хотите получить из свойства, если у свойства нет значения? То, что php в некоторых случаях при отсутствии типов выполняет неявное приведение к null не распространяется на ситуации, когда вы явно указали типы, а значит хотите явного поведения.
А вот Null - это уже значение, которое используется для передачи отсутствия значения как значение.

2. Если заботитесь о качестве кода, то да. Все абсолютно логично, php подсказывает вам, что вы вероятно забыли инициализировать переменную, т.е. допустили ошибку, обратившись к переменной раньше, чем положили в нее значение.
Здесь нет ничего "громоздкого", просто вы явно описываете поведение. Можете этого, конечно, не делать, например не использовать указание типов и расчитывать на то, что php сам что-нибудь подставит - но, очевидно, это ненадежный путь, ведущий к ошибкам.
В идеале, вы должны задать свойству корректное значение, а затем его использовать. Т.е. использовать 1 единственный тип. Не всегда логика это позволяет и тогда нужно инициализировать переменную значением null.

Хороший код тот, который очевиден и понятен с первого взгляда, а не в котором мало букв. Указывая типы вы всегда знаете что за тип лежит в конкретной переменной и вам не нужно продумывать обработку других типов. Даже когда вы пишете ?int, значит кроме целого числа там еще и null может быть, и это придется учитывать при всех манипуляцих с этой переменной. И вот это, и будет делать код более сложным. А если вы не сделаете обработку всех доступных типов, тогда поведение кода может стать непредсказуемым.
Ответ написан
Комментировать
Rsa97
@Rsa97
Для правильного вопроса надо знать половину ответа
1. Нет, по умолчанию типизированное свойство не инициализировано
class Product
{
    private int $parentId;

    private $nonTyped;

    public function __construct(
        private readonly int $id
    ) {
    }
}

$obj = new Product(1);
var_dump($obj);

// class \Product#2 (3) {
//   private int $parentId => *uninitialized*
//   private $nonTyped => NULL
//   private readonly int $id => int(1)
// }


2. Если это свойство необязательное, то вариантов три:
- не обращаться к свойству до его инициализации;
- инициализировать свойство значением по умолчанию при определении;
- делать коалесценцию в геттере, возвращая значение по умолчанию (return $this->parentId ?? null;).
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы