Как избежать ошибки "Fatal error: Uncaught Error: Typed property Product::$parentId must not be accessed before initialization" и улучшить структуру кода для инициализации свойств в PHP?
Ошибка "Доступ к типизированному свойству должен выполняться после инициализации" возникает тогда, когда вы пытаетесь обратиться к типизированному свойству объекта до его явной инициализации.
Чтобы избежать этой ошибки и улучшить структуру кода для инициализации свойств в PHP, рекомендуется присваивать значения свойствам объекта сразу после его создания, как показано в примере ниже:
```php
class Product {
public int $id;
public string $name;
public int $parentId = 0; // явная инициализация
}
$product = new Product();
$product->id = 1;
$product->name = "Product 1";
echo $product->parentId; // выведет 0
```
В этом примере свойство `$parentId` инициализируется явно значением по умолчанию после объявления свойства. Таким образом, при создании объекта `Product`, все его свойства будут иметь значения по умолчанию, и доступ к ним будет возможен без ошибок.
Используйте Constructor property promotion чтобы писать меньше букв) <br/> <pre><code class="php"><?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';
}</code></pre> <br/> <br/> Либо уберите типизацию у свойства и при <code>public $parentId;</code> ошибки не будет. Всё как и написано в тексте ошибки, нельзя обратиться к <b>типизированному</b> свойству до его инициализации, а значит нужно либо задать значение по умолчанию при описании свойства, либо через конструктор, либо вызвав setter. <br/> <br/> uninitialized и typed properties <br/> <a href="https://php.watch/versions/7.4/typed-properties#uninitialized" rel="nofollow">https://php.watch/versions/7.4/typed-properties#un...</a>
<blockquote>1. Разве по умолчанию свойства не null?<br/> 2. У меня 20-30 свойств. Для каждого что-ли делать так? Код какой-то не логичный и громоздкий.</blockquote> <br/> 1. Нет, в данном случае у свойства нет значения, оно не инициализировано. Какое значение вы хотите получить из свойства, если у свойства нет значения? То, что php в некоторых случаях при отсутствии типов выполняет неявное приведение к null не распространяется на ситуации, когда вы явно указали типы, а значит хотите явного поведения. <br/> А вот Null - это уже значение, которое используется для передачи отсутствия значения как значение. <br/> <br/> 2. Если заботитесь о качестве кода, то да. Все абсолютно логично, php подсказывает вам, что вы вероятно забыли инициализировать переменную, т.е. допустили ошибку, обратившись к переменной раньше, чем положили в нее значение. <br/> Здесь нет ничего "громоздкого", просто вы явно описываете поведение. Можете этого, конечно, не делать, например не использовать указание типов и расчитывать на то, что php сам что-нибудь подставит - но, очевидно, это ненадежный путь, ведущий к ошибкам. <br/> В идеале, вы должны задать свойству корректное значение, а затем его использовать. Т.е. использовать 1 единственный тип. Не всегда логика это позволяет и тогда нужно инициализировать переменную значением null. <br/> <br/> Хороший код тот, который очевиден и понятен с первого взгляда, а не в котором мало букв. Указывая типы вы всегда знаете что за тип лежит в конкретной переменной и вам не нужно продумывать обработку других типов. Даже когда вы пишете ?int, значит кроме целого числа там еще и null может быть, и это придется учитывать при всех манипуляцих с этой переменной. И вот это, и будет делать код более сложным. А если вы не сделаете обработку всех доступных типов, тогда поведение кода может стать непредсказуемым.
1. Нет, по умолчанию типизированное свойство не инициализировано <br/> <pre><code class="php">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)
// }</code></pre> <br/> <br/> 2. Если это свойство необязательное, то вариантов три: <br/> - не обращаться к свойству до его инициализации; <br/> - инициализировать свойство значением по умолчанию при определении; <br/> - делать коалесценцию в геттере, возвращая значение по умолчанию ( <code class="php">return $this->parentId ?? null;</code> ).