Tại sao tôi đột nhiên nhận được một thuộc tính Typed Typed không được truy cập trước khi khởi tạo lỗi lỗi khi giới thiệu gợi ý loại thuộc tính?


10

Tôi đã cập nhật các định nghĩa lớp của mình để sử dụng các gợi ý loại thuộc tính mới được giới thiệu, như thế này:

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

Nhưng khi cố gắng lưu thực thể của tôi trên Học thuyết, tôi gặp lỗi khi nói:

Thuộc tính gõ không được truy cập trước khi khởi tạo

Điều này không chỉ xảy ra với $idhoặc $createdAt, mà còn xảy ra với $valuehoặc $updatedAt, đó là các thuộc tính nullable.

Câu trả lời:


20

Do PHP 7.4 giới thiệu gợi ý kiểu cho các thuộc tính, điều đặc biệt quan trọng là cung cấp các giá trị hợp lệ cho tất cả các thuộc tính, để tất cả các thuộc tính có các giá trị khớp với các kiểu khai báo của chúng.

Một biến chưa bao giờ được gán không có nullgiá trị, nhưng nó ở undefinedtrạng thái, sẽ không bao giờ khớp với bất kỳ loại khai báo nào . undefined !== null.

Đối với mã ở trên, nếu bạn đã làm:

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

Bạn sẽ nhận được:

Lỗi nghiêm trọng: Lỗi chưa được xử lý: Thuộc tính đã nhập Foo :: $ val không được truy cập trước khi khởi tạo

$valkhông phải stringcũng không phải nullkhi truy cập nó.

Cách để giải quyết vấn đề này là gán giá trị cho tất cả các thuộc tính của bạn khớp với các loại khai báo. Bạn có thể làm điều này làm giá trị mặc định cho thuộc tính hoặc trong quá trình xây dựng, tùy thuộc vào sở thích của bạn và loại tài sản.

Ví dụ, đối với những điều trên bạn có thể làm:

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

Bây giờ tất cả các thuộc tính sẽ có một giá trị hợp lệ và thể hiện sẽ ở trạng thái hợp lệ.

Điều này có thể xảy ra đặc biệt thường xuyên khi bạn đang dựa vào các giá trị đến từ DB cho các giá trị thực thể. Ví dụ: ID được tạo tự động, hoặc tạo và / hoặc giá trị cập nhật; mà thường được để lại như là một mối quan tâm DB.

Đối với ID được tạo tự động, cách chuyển tiếp được đề xuất là thay đổi khai báo kiểu thành ?int $id = null. Đối với tất cả phần còn lại, chỉ cần chọn một giá trị phù hợp cho loại tài sản.


-5

Lỗi của tôi

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

Giải pháp của tôi - thêm phương thức tiếp theo vào lớp:

public function __sleep()
{
    return [];
}

1
Vui lòng đọc chính xác câu hỏi, sau đó trả lời dựa trên câu hỏi, không hoàn toàn dựa trên vấn đề / giải pháp của bạn.
MAChitgarha
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.