Perché all'improvviso viene visualizzato l'errore "Impossibile accedere alla proprietà digitata prima dell'inizializzazione" quando si introducono suggerimenti sul tipo di proprietà?


10

Ho aggiornato le definizioni delle mie classi per utilizzare i suggerimenti sul tipo di proprietà appena introdotti, in questo modo:

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

Ma quando provo a salvare la mia entità su Doctrine ricevo un errore che dice:

Non è possibile accedere alla proprietà digitata prima dell'inizializzazione

Questo non accade solo con $ido $createdAt, ma accade anche con $valueo $updatedAt, che sono proprietà nullable.

Risposte:


20

Poiché PHP 7.4 introduce il suggerimento del tipo per le proprietà, è particolarmente importante fornire valori validi per tutte le proprietà, in modo che tutte le proprietà abbiano valori che corrispondono ai loro tipi dichiarati.

Una variabile che non è mai stata assegnata non ha un nullvalore, ma è su uno undefinedstato, che non corrisponderà mai a nessun tipo dichiarato . undefined !== null.

Per il codice sopra, se hai fatto:

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

Otterresti:

Errore irreversibile: errore non rilevato: non è possibile accedere alla proprietà digitata Foo :: $ val prima dell'inizializzazione

Poiché $valnon è né stringnullquando si accede ad esso.

Il modo per aggirare questo è quello di assegnare valori a tutte le proprietà che corrispondono ai tipi dichiarati. Puoi farlo come valori predefiniti per la proprietà o durante la costruzione, a seconda delle tue preferenze e del tipo di proprietà.

Ad esempio, per quanto sopra potresti fare:

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

Ora tutte le proprietà avrebbero un valore valido e l'istanza sarebbe su uno stato valido.

Questo può colpire particolarmente spesso quando si fa affidamento su valori che provengono dal DB per i valori di entità. Ad esempio ID generati automaticamente o valori di creazione e / o aggiornati; che spesso vengono lasciati come problemi DB.

Per gli ID generati automaticamente, la via da seguire consigliata è cambiare la dichiarazione del tipo in ?int $id = null. Per tutto il resto, basta scegliere un valore appropriato per il tipo di proprietà.


-5

Errore mio:

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

La mia soluzione: aggiungi il metodo successivo alla classe:

public function __sleep()
{
    return [];
}

1
Si prega di leggere la domanda con precisione, quindi rispondere in base alla domanda, non totalmente in base al problema / soluzione.
MAChitgarha,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.