PHP 8: Quảng cáo tài sản xây dựng


Cá nhân tôi luôn sử dụng các đối tượng giá trị và đối tượng truyền dữ liệu trong các dự án của mình. Tôi thậm chí còn viết một bài riêng về cách xử lý dữ liệu trong mã của chúng tôi cách đây không lâu.

Đương nhiên, tôi rất hài lòng với RFC quảng bá thuộc tính của hàm tạo, nó đã được thông qua và sẽ được thêm vào PHP 8. Bạn thấy đấy, tính năng này giúp giảm rất nhiều mã soạn sẵn khi xây dựng các đối tượng đơn giản như VO và DTO.

Nói tóm lại: tăng cường thuộc tính cho phép bạn kết hợp tất cả các trường lớp, định nghĩa hàm tạo và phép gán biến thành một cú pháp, trong danh sách tham số cấu trúc.

Vì vậy, thay vì làm điều này:

class CustomerDTO
{
    public string $name;

    public string $email;

    public DateTimeImmutable $birth_date;

    public function __construct(
        string $name, 
        string $email, 
        DateTimeImmutable $birth_date
    ) {
        $this->name = $name;
        $this->email = $email;
        $this->birth_date = $birth_date;
    }
}

Bạn sẽ viết điều này:

class CustomerDTO
{
    public function __construct(
        public string $name, 
        public string $email, 
        public DateTimeImmutable $birth_date,
    ) {}
}

Hãy xem nó hoạt động như thế nào!


# Làm thế nào nó hoạt động

Ý tưởng cơ bản rất đơn giản: loại bỏ tất cả các thuộc tính của lớp và các phép gán biến, đồng thời đặt tiền tố cho các tham số của hàm tạo bằng public, protected hoặc private. PHP sẽ lấy cú pháp mới đó và chuyển đổi nó thành cú pháp bình thường trước khi thực sự thực thi mã.

Vì vậy, nó đi từ đây:

class MyDTO
{
    public function __construct(
        public string $name = 'Brent',
    ) {}
}

Về điều này:

class MyDTO
{
    public string $name;

    public function __construct(
        string $name = 'Brent'
    ) {
        $this->name = $name;
    }
}

Và chỉ thực hiện nó sau đó.

Nhân tiện, hãy lưu ý rằng giá trị mặc định không được đặt trên thuộc tính lớp mà trên đối số phương thức trong hàm tạo.

Vì vậy, hãy xem những gì thuộc tính được quảng cáo có thể và không thể làm được, có khá nhiều điều phức tạp nho nhỏ đáng nói!


# Chỉ có trong hàm tạo

Thuộc tính được thăng cấp chỉ có thể được sử dụng trong hàm tạo. Điều đó có vẻ hiển nhiên nhưng tôi nghĩ cần phải đề cập đến điều này, chỉ để cho rõ ràng.

Nhận thấy một tpyo? Bạn có thể gửi PR để sửa nó. Nếu bạn muốn cập nhật về những gì đang diễn ra trên blog này, bạn có thể Theo dõi danh sách gửi thư của tôi: gửi email đến [email protected] và tôi sẽ thêm bạn vào danh sách.

# Không được phép trùng lặp

Bạn không thể khai báo thuộc tính lớp và thuộc tính được thăng cấp có cùng tên. Điều đó cũng khá hợp lý, vì thuộc tính được thăng cấp chỉ được dịch sang thuộc tính lớp trong thời gian chạy.

class MyClass
{
    public string $a;

    public function __construct(
        public string $a,
    ) {}
}

# Cho phép thuộc tính chưa được gõ

Bạn được phép quảng cáo các thuộc tính chưa được gõ, mặc dù tôi cho rằng ngày nay với PHP hiện đại, tốt hơn hết bạn nên gõ mọi thứ.

class MyDTO
{
    public function __construct(
        public $untyped,
    ) {}
}

# Mặc định đơn giản

Thuộc tính được thăng hạng có thể có giá trị mặc định, nhưng các biểu thức như new … không được cho phép.

public function __construct(
    public string $name = 'Brent',
    public DateTimeImmutable $date = new DateTimeImmutable(),
) {}

# Kết hợp các thuộc tính được thăng cấp và bình thường

Không phải tất cả các thuộc tính của hàm tạo đều được quảng bá, bạn có thể kết hợp và kết hợp.

class MyClass
{
    public string $b;

    public function __construct(
        public string $a,
        string $b,
    ) {
        $this->b = $b;
    }
}

Tôi muốn nói: hãy cẩn thận khi trộn các cú pháp, nếu nó làm cho mã kém rõ ràng hơn, thay vào đó hãy cân nhắc sử dụng một hàm tạo thông thường.


# Truy cập các thuộc tính được thăng hạng từ phần thân hàm tạo

Bạn được phép đọc các thuộc tính được thăng cấp trong nội dung hàm tạo. Điều này có thể hữu ích nếu bạn muốn thực hiện kiểm tra xác thực bổ sung. Bạn có thể sử dụng cả biến cục bộ và biến thể hiện, cả hai đều hoạt động tốt.

public function __construct(
    public int $a,
    public int $b,
) {
    assert($this->a >= 100);

    if ($b >= 0) {
        throw new InvalidArgumentException('…');
    }
}

Bạn có thể thêm nhận xét tài liệu trên các thuộc tính được quảng cáo và chúng vẫn có sẵn thông qua phản ánh.

class MyClass 
{
    public function __construct(
        
        public $a,
    ) {}
}
$property = new ReflectionProperty(MyClass::class, 'a');

$property->getDocComment(); 

# Thuộc tính

Giống như khối tài liệu, thuộc tính được phép trên thuộc tính được quảng cáo. Khi được dịch mã, chúng sẽ xuất hiện cả trên tham số hàm tạo cũng như thuộc tính lớp.

class MyClass
{
    public function __construct(
        
        public $a,  
    ) {}
}

Sẽ được dịch sang:

class MyClass 
{
    
    public $a;
 
    public function __construct(
        
        $a,
    ) {
        $this->a = $a;
    }
}

# Không được phép trong hàm tạo trừu tượng

Tôi thậm chí còn không biết các hàm tạo trừu tượng là một thứ, nhưng rồi đây! Thuộc tính được quảng cáo không được phép trong đó.

abstract class A
{
    abstract public function __construct(
        public string $a,
    ) {}
}

# Được phép trong đặc điểm

Mặt khác, họ được phép có những đặc điểm. Điều này có ý nghĩa vì cú pháp được dịch mã cũng có giá trị về các đặc điểm.

trait MyTrait
{
    public function __construct(
        public string $a,
    ) {}
}

# var không được hỗ trợ

Ý tôi là, những nhà phát triển PHP có kinh nghiệm có thể đã sử dụng var trong quá khứ xa xôi để khai báo các biến lớp. Nó không được phép với quảng cáo của nhà xây dựng. Chỉ một public, protectedprivate là những từ khóa hợp lệ.

public function __construct(
    var string $a,
) {}

# Không thể thăng cấp các tham số đa dạng

Vì bạn không thể chuyển đổi sang loại array of typekhông thể quảng bá các tham số biến đổi.

public function __construct(
    public string ...$a,
) {}

Vẫn đang chờ thuốc generic…


# Phản ánh cho isPromoted

Cả hai ReflectionPropertyReflectionParameter có một cái mới isPromoted phương thức để kiểm tra xem thuộc tính lớp hoặc tham số phương thức có được thăng cấp hay không.


# Di sản

Vì các hàm tạo PHP không cần tuân theo khai báo của hàm tạo gốc nên có rất ít điều cần nói: sự kế thừa được cho phép. Tuy nhiên, nếu bạn cần truyền các thuộc tính từ hàm tạo con sang hàm tạo gốc, thì bạn sẽ cần chuyển chúng theo cách thủ công:

class A
{
    public function __construct(
        public $a,
    ) {}
}

class B extends A
{
    public function __construct(
        $a,
        public $b,    
    ) {
        parent::__construct($a);
    }
}

Đó là về việc quảng bá tài sản! Tôi chắc chắn sẽ sử dụng chúng, còn bạn thì sao? Hãy cho tôi biết qua Twitter hoặc e-mail!




Leave a Comment

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *

Scroll to Top