PHP 8: trước và sau


Chỉ còn vài tháng nữa là PHP 8 sẽ được phát hành và thành thật mà nói thì có rất nhiều tính năng hay. Trong bài đăng này, tôi muốn chia sẻ tác động thực tế mà PHP 8 sẽ có đối với mã của riêng tôi.

# Người đăng ký sự kiện có thuộc tính

Tôi sẽ cố gắng không lạm dụng các thuộc tính, nhưng tôi nghĩ việc định cấu hình trình xử lý sự kiện là một ví dụ về chú thích mà tôi sẽ sử dụng rộng rãi.

Bạn có thể biết rằng gần đây tôi đang làm việc trên các hệ thống có nguồn gốc sự kiện và tôi có thể cho bạn biết: có rất nhiều cấu hình sự kiện cần thực hiện. Lấy máy chiếu đơn giản này làm ví dụ:



class CartsProjector implements Projector
{
    use ProjectsEvents;

    protected array $handlesEvents = (
        CartStartedEvent::class => 'onCartStarted',
        CartItemAddedEvent::class => 'onCartItemAdded',
        CartItemRemovedEvent::class => 'onCartItemRemoved',
        CartExpiredEvent::class => 'onCartExpired',
        CartCheckedOutEvent::class => 'onCartCheckedOut',
        CouponAddedToCartItemEvent::class => 'onCouponAddedToCartItem',
    );

    public function onCartStarted(CartStartedEvent $event): void
    {  }

    public function onCartItemAdded(CartItemAddedEvent $event): void
    {  }

    public function onCartItemRemoved(CartItemRemovedEvent $event): void
    {  }

    public function onCartCheckedOut(CartCheckedOutEvent $event): void
    {  }

    public function onCartExpired(CartExpiredEvent $event): void
    {  }

    public function onCouponAddedToCartItem(CouponAddedToCartItemEvent $event): void
    {  }
}

PHP 7.4

Có hai thuộc tính lợi ích sẽ mang lại cho tôi:

  • Cấu hình và trình xử lý sự kiện được kết hợp với nhau, tôi không cần phải cuộn lên đầu tệp để biết liệu trình xử lý có được định cấu hình chính xác hay không.
  • Tôi không còn phải bận tâm đến việc viết và quản lý tên phương thức dưới dạng chuỗi nữa: IDE của bạn không thể tự động hoàn thành chúng, không có phân tích tĩnh về lỗi chính tả và việc đổi tên phương thức không hoạt động.

May mắn thay, PHP 8 giải quyết được những vấn đề sau:

class CartsProjector implements Projector
{
    use ProjectsEvents;

    
    public function onCartStarted(CartStartedEvent $event): void
    {  }

    
    public function onCartItemAdded(CartItemAddedEvent $event): void
    {  }

    
    public function onCartItemRemoved(CartItemRemovedEvent $event): void
    {  }

    
    public function onCartCheckedOut(CartCheckedOutEvent $event): void
    {  }

    
    public function onCartExpired(CartExpiredEvent $event): void
    {  }

    
    public function onCouponAddedToCartItem(CouponAddedToCartItemEvent $event): void
    {  }
}

PHP 8

# Tĩnh thay vì khối tài liệu

Một cái nhỏ hơn, nhưng cái này sẽ có tác động hàng ngày. Tôi thường thấy mình vẫn cần các khối tài liệu vì hai điều: kiểu trả về tĩnh và kiểu tổng quát. Vấn đề thứ hai vẫn chưa thể giải quyết được, nhưng may mắn là vấn đề đầu tiên sẽ có trong PHP 8!

Khi tôi viết điều này bằng PHP 7.4:


public static function new()
{
    return new static();
}

PHP 7.4

Bây giờ tôi sẽ có thể viết:

public static function new(): static
{
    return new static();
}

PHP 8

Nếu bạn đọc blog của tôi, bạn sẽ biết tôi đã viết khá nhiều về cách sử dụng hệ thống kiểu của PHP kết hợp với các đối tượng truyền dữ liệu. Đương nhiên, tôi sử dụng rất nhiều DTO trong mã của riêng mình, vì vậy bạn có thể tưởng tượng tôi hạnh phúc như thế nào khi có thể viết lại dòng này:

class CustomerData extends DataTransferObject
{
    public string $name;

    public string $email;

    public int $age;
    
    public static function fromRequest(
        CustomerRequest $request
    ): self {
        return new self((
            'name' => $request->get('name'),
            'email' => $request->get('email'),
            'age' => $request->get('age'),
        ));
    }
}

$data = CustomerData::fromRequest($customerRequest);

PHP 7.4

Như thế này:

class CustomerData
{
    public function __construct(
        public string $name,
        public string $email,
        public int $age,
    ) {}
}

$data = new CustomerData(...$customerRequest->validated());

PHP 8

Lưu ý việc sử dụng cả khuyến mãi thuộc tính hàm tạo, cũng như các đối số được đặt tên. Có, chúng có thể được truyền bằng cách sử dụng các mảng được đặt tên và toán tử trải rộng!

# Enums và biểu thức so khớp

Đôi khi bạn có thấy mình sử dụng một enum với một số phương thức trên đó, điều đó sẽ cho kết quả khác dựa trên giá trị enum không?


class InvoiceState extends Enum
{
    private const PENDING = 'pending';
    private const PAID = 'paid';

    public function getColour(): string
    {
        return (
            self::PENDING => 'orange',
            self::PAID => 'green',
        )($this->value) ?? 'gray';   
    }
}

PHP 7.4

Tôi cho rằng đối với các điều kiện phức tạp hơn, tốt hơn hết bạn nên sử dụng mẫu trạng thái, tuy nhiên có những trường hợp một enum là đủ. Cú pháp mảng kỳ lạ này đã là một cách viết tắt cho một điều kiện dài dòng hơn:


class InvoiceState extends Enum
{
    private const PENDING = 'pending';
    private const PAID = 'paid';

    public function getColour(): string
    {
        if ($this->value === self::PENDING) {
            return 'orange';
        }
    
        if ($this->value === self::PAID) {
            return 'green'
        }

        return 'gray';
    }
}

PHP 7.4 — thay thế

Nhưng với PHP 8, chúng ta có thể sử dụng match biểu hiện thay thế!


class InvoiceState extends Enum
{
    private const PENDING = 'pending';
    private const PAID = 'paid';

    public function getColour(): string
    {
        return match ($this->value) {
            self::PENDING => 'orange',
            self::PAID => 'green',
            default => 'gray',
        };
    }
}

PHP 8

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.

# Các loại liên kết thay vì các khối tài liệu

Khi tôi đề cập đến static kiểu trả về trước đây, tôi đã quên một trường hợp sử dụng khác trong đó yêu cầu gợi ý loại docblock: kiểu kết hợp. Ít nhất, chúng đã được yêu cầu trước đây vì PHP 8 hỗ trợ chúng một cách nguyên bản!


public function sanitize($input): string;

PHP 7.4

public function sanitize(string|int $input): string;

PHP 8

# Ném biểu thức

Trước PHP 8, bạn không thể sử dụng throw trong một biểu thức, nghĩa là bạn phải thực hiện các kiểm tra rõ ràng như sau:

public function (array $input): void
{
    if (! isset($input('bar'))) {
        throw BarIsMissing::new();
    }
    
    $bar = $input('bar');

    
}

PHP 7.4

Trong PHP 8, throw đã trở thành một biểu thức, nghĩa là bạn có thể sử dụng nó như sau:

public function (array $input): void
{
    $bar = $input('bar') ?? throw BarIsMissing::new();

    
}

PHP 8

# Toán tử nullsafe

Nếu bạn quen thuộc với toán tử hợp nhất null thì bạn cũng đã quen với những thiếu sót của nó: nó không hoạt động với lệnh gọi phương thức. Thay vào đó bạn cần kiểm tra trung gian hoặc dựa vào optional người trợ giúp được cung cấp bởi một số khung:

$startDate = $booking->getStartDate();

$dateAsString = $startDate ? $startDate->asDateTimeString() : null;

PHP 7.4

Với việc bổ sung toán tử nullsafe, giờ đây chúng ta có thể có hành vi giống như hợp nhất null trên các phương thức!

$dateAsString = $booking->getStartDate()?->asDateTimeString();

PHP 8

Tính năng PHP 8 yêu thích của bạn là gì? Hãy cho tôi biết qua Twitter hoặc qua 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