Neden özellik türü ipuçlarını tanıtırken birden bire "Yazılan özelliğe başlatmadan önce erişilmemelidir" hatası alıyorum?


10

Yeni tanıtılan özellik türü ipuçlarından yararlanmak için sınıf tanımlarımı güncelledim:

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

Ama varlığımı Doktrine kaydetmeye çalışırken şöyle bir hata alıyorum:

Başlatmadan önce yazılan özelliğe erişilmemelidir

Bu sadece $idveya ile değil $createdAt, aynı zamanda nullable özellikler olan $valueveya ile de olur $updatedAt.

Yanıtlar:


20

PHP 7.4, özellikler için tür ipucu verdiğinden, tüm özellikler için geçerli değerler sağlamak özellikle önemlidir, böylece tüm özellikler, bildirilen türleriyle eşleşen değerlere sahiptir.

Daha önce atanmamış olan bir değişkenin nulldeğeri yoktur, ancak bildirilen herhangi bir türle hiçbir zaman eşleşmeyecek bir undefineddurumdur . .undefined !== null

Yukarıdaki kod için şunu yaptıysanız:

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

Şunları elde edersiniz:

Önemli hata: Yakalanmadı Hata: Başlatmadan önce Foo :: $ val tipine erişilmemeli

Çünkü $valne ne stringde nullona erişirken.

Bu sorunu aşmanın yolu, bildirilen türlerle eşleşen tüm özelliklerinize değer atamaktır. Tercihinize ve mülkün türüne bağlı olarak bunu mülk için varsayılan değerler olarak veya inşaat sırasında yapabilirsiniz.

Örneğin, yukarıdakiler için şunları yapabilirsiniz:

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

Şimdi tüm özelliklerin geçerli bir değeri olur ve örnek geçerli bir durumda olur.

Bu durum özellikle varlık değerleri için DB'den gelen değerlere güveniyorsanız vurulabilir. Örneğin, otomatik oluşturulan kimlikler veya oluşturma ve / veya güncellenmiş değerler; ve genellikle DB sorunu olarak kalır.

Otomatik olarak oluşturulan kimlikler için önerilen ileri yol , tür bildirimini olarak değiştirmektir ?int $id = null. Geri kalan her şey için, mülkün türü için uygun bir değer seçmeniz yeterlidir.


-5

Benim hatam:

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

Benim çözümüm - sınıfa bir sonraki yöntemi ekleyin:

public function __sleep()
{
    return [];
}

1
Lütfen soruyu tam olarak okuyun, ardından tamamen sorununuzu / çözümünüzü değil, soruyu temel alarak cevaplayın.
MAChitgarha
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.