Pourquoi j'obtiens soudainement une erreur «La propriété typée ne doit pas être accessible avant l'initialisation» lors de l'introduction d'indications de type de propriétés?

10

J'ai mis à jour mes définitions de classe pour utiliser les indications de type de propriété nouvellement introduites, comme ceci:

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

Mais lorsque j'essaie de sauvegarder mon entité dans Doctrine, je reçois une erreur disant:

La propriété typée ne doit pas être accessible avant l'initialisation

Cela se produit non seulement avec $idou $createdAt, mais aussi avec $valueou $updatedAt, qui sont des propriétés nullables.

yivi
la source

Réponses:

21

Étant donné que PHP 7.4 introduit une indication de type pour les propriétés, il est particulièrement important de fournir des valeurs valides pour toutes les propriétés, afin que toutes les propriétés aient des valeurs qui correspondent à leurs types déclarés.

Une variable qui n'a jamais été affectée n'a pas de nullvaleur, mais elle se trouve dans un undefinedétat qui ne correspondra à aucun type déclaré . undefined !== null.

Pour le code ci-dessus, si vous l'avez fait:

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

Vous obtiendriez:

Erreur fatale: erreur non interceptée: la propriété typée Foo :: $ val ne doit pas être accessible avant l'initialisation

Puisque $valn'est ni stringni nulllors de l'accès.

Le moyen de contourner ce problème consiste à attribuer des valeurs à toutes vos propriétés qui correspondent aux types déclarés. Vous pouvez le faire en tant que valeurs par défaut pour la propriété ou pendant la construction, selon vos préférences et le type de propriété.

Par exemple, pour ce qui précède, vous pouvez faire:

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

Maintenant, toutes les propriétés auraient une valeur valide et l'instance serait dans un état valide.

Cela peut se produire particulièrement souvent lorsque vous comptez sur des valeurs provenant de la base de données pour les valeurs d'entité. Par exemple, les ID générés automatiquement ou les valeurs de création et / ou mises à jour; qui sont souvent laissés comme une préoccupation DB.

Pour les ID générés automatiquement, la voie à suivre recommandée consiste à remplacer la déclaration de type par ?int $id = null. Pour tout le reste, choisissez simplement une valeur appropriée pour le type de propriété.

yivi
la source
-5

Mon erreur:

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

Ma solution - ajoutez la méthode suivante à la classe:

public function __sleep()
{
    return [];
}
Lebnik
la source
1
Veuillez lire la question avec précision, puis répondre en fonction de la question, pas totalement en fonction de votre problème / solution.
MAChitgarha