Mengapa saya tiba-tiba mendapatkan kesalahan "Properti yang diketik tidak boleh diakses sebelum inisialisasi" ketika memperkenalkan petunjuk jenis properti?

10

Saya telah memperbarui definisi kelas saya untuk menggunakan petunjuk tipe properti yang baru diperkenalkan, seperti ini:

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

Tetapi ketika mencoba menyelamatkan entitas saya di Doktrin, saya mendapat pesan kesalahan:

Properti yang diketik tidak boleh diakses sebelum inisialisasi

Ini tidak hanya terjadi dengan $idatau $createdAt, tetapi juga terjadi dengan $valueatau $updatedAt, yang merupakan properti nullable.

yivi
sumber

Jawaban:

20

Karena PHP 7.4 memperkenalkan petunjuk jenis untuk properti, sangat penting untuk memberikan nilai yang valid untuk semua properti, sehingga semua properti memiliki nilai yang cocok dengan tipe yang dinyatakan.

Variabel yang belum pernah ditugaskan tidak memiliki nullnilai, tetapi itu dalam undefinedkeadaan, yang tidak akan pernah cocok dengan tipe yang dideklarasikan . undefined !== null.

Untuk kode di atas, jika Anda melakukannya:

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

Anda akan mendapatkan:

Kesalahan fatal: Kesalahan tidak tertangkap: Properti diketik Foo :: $ val tidak boleh diakses sebelum inisialisasi

Karena $valtidak stringjuga nullsaat mengaksesnya.

Cara menyiasatinya adalah dengan menetapkan nilai ke semua properti Anda yang cocok dengan tipe yang dideklarasikan. Anda dapat melakukan ini sebagai nilai default untuk properti atau selama konstruksi, tergantung pada preferensi Anda dan jenis properti.

Misalnya, untuk hal di atas Anda bisa melakukan:

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

Sekarang semua properti akan memiliki nilai yang valid dan turunannya akan berada pada status yang valid.

Ini bisa sangat sering terjadi ketika Anda mengandalkan nilai yang berasal dari DB untuk nilai entitas. Misalnya ID yang dibuat secara otomatis, atau kreasi dan / atau nilai yang diperbarui; yang sering dibiarkan menjadi perhatian DB.

Untuk ID yang dibuat secara otomatis, cara maju yang disarankan adalah mengubah deklarasi tipe menjadi ?int $id = null. Untuk yang lainnya, cukup pilih nilai yang sesuai untuk jenis properti.

yivi
sumber
-5

Kesalahan saya:

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

Solusi saya - tambahkan metode selanjutnya ke kelas:

public function __sleep()
{
    return [];
}
Lebnik
sumber
1
Harap baca pertanyaan dengan tepat, lalu jawab berdasarkan pertanyaan, tidak sepenuhnya berdasarkan masalah / solusi Anda.
MAChitgarha