Toutes les valeurs des propriétés doivent être initialisées dans __construct()
, surtout pas dans la signature !
Même si vous n’utilisez pas les Partial Objects de doctrine, on ne maîtrise pas totalement ce qui sera fait avec notre entité.
En effet, elle peut avoir été chargée par une librairie externe, avoir été modifiée dans un évènement, etc.
class Foo
{
private int $defaultProperty = 1;
public function __construct(private string $property)
{
}
public function getDefaultProperty(): int
{
return $this->defaultProperty;
}
public function getProperty(): string
{
return $this->property;
}
}
class FooRepository
{
public function getPartial(): Foo
{
return $this
->createQueryBuilder('foo')
->select('PARTIAL foo.{property}')
}
}
$foo = $fooRepository->getPartial();
// On a bien la valeur en base de données pour $property, tout va bien
$foo->getProperty();
// On n'a pas la valeur en base de données pour $defaultProperty, on a la valeur qui a été définie dans le code source !
$foo->getDefaultProperty();
Pour ne pas avoir ce problème, on définit toutes les valeurs dans __construct()
,
qui ne sera pas appelé par Doctrine lors de la création d’une entité : il utilise
ReflectionClass::newInstanceWithoutConstructor.
class Foo
{
private int $defaultProperty;
public function __construct(private string $property)
{
$this->defaultProperty = 1;
}
public function getDefaultProperty(): int
{
return $this->defaultProperty;
}
public function getProperty(): string
{
return $this->property;
}
}
$foo = $fooRepository->getPartial();
// On a bien la valeur en base de données pour $property, tout va bien
$foo->getProperty();
// PHP va lever une exception de type \Error : Typed property Foo::$defaultProperty must not be accessed before initialization
// Ce qui paraît cohérent : on n'a pas chargé cette donnée, mais on essaye d'y accéder alors qu'on ne devrait pas
$foo->getDefaultProperty();