PHP 8: đối số được đặt tên – Stitcher.io


Đó là một kết quả gần đúng, nhưng các đối số được đặt tên — còn được gọi là các tham số được đặt tên — được hỗ trợ trong PHP 8! Trong bài đăng này, tôi sẽ thảo luận chi tiết về chúng, nhưng trước tiên hãy để tôi cho bạn thấy chúng trông như thế nào bằng một vài ví dụ thực tế:

setcookie(
    name: 'test',
    expires: time() + 60 * 60 * 2,
);

Các đối số được đặt tên được sử dụng trên hàm PHP tích hợp

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

$data = new CustomerData(
    name: $input('name'),
    email: $input('email'),
    age: $input('age'),
);

DTO sử dụng các thuộc tính được thăng cấp cũng như các đối số được đặt tên

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

Các đối số được đặt tên cũng hỗ trợ trải rộng mảng

Bạn có thể đoán được từ các ví dụ: đối số được đặt tên cho phép bạn chuyển dữ liệu đầu vào vào một hàm, dựa trên tên đối số của chúng thay vì thứ tự đối số.

Tôi cho rằng các đối số được đặt tên là một tính năng tuyệt vời sẽ có tác động đáng kể đến công việc lập trình hàng ngày của tôi. Tuy nhiên, có thể bạn đang thắc mắc về các chi tiết: nếu bạn nhập sai tên thì sao với cú pháp trải rộng mảng đó? Chà, chúng ta hãy xem xét sâu hơn tất cả những câu hỏi đó.

# Tại sao đặt tên cho đối số?

Giả sử tính năng này là một tính năng gây tranh cãi nhiều và có một số lập luận phản đối việc không thêm chúng. Tuy nhiên, tôi muốn nói rằng lợi ích của chúng vượt xa nỗi lo về các vấn đề tương thích ngược hoặc các API cồng kềnh. Theo cách tôi thấy, chúng sẽ cho phép chúng tôi viết mã sạch hơn và linh hoạt hơn.

Đầu tiên, các đối số được đặt tên cho phép bạn bỏ qua các giá trị mặc định. Hãy xem lại ví dụ về cookie:

setcookie(
    name: 'test',
    expires: time() + 60 * 60 * 2,
);

Chữ ký phương thức của nó thực sự là như sau:

setcookie ( 
    string $name, 
    string $value = "", 
    int $expires = 0, 
    string $path = "", 
    string $domain = "", 
    bool $secure = false, 
    bool $httponly = false,
) : bool

Trong ví dụ tôi đã trình bày, chúng tôi không cần đặt cookie $value, nhưng chúng tôi cần phải đặt thời gian hết hạn. Các đối số được đặt tên làm cho lệnh gọi phương thức này ngắn gọn hơn một chút:

setcookie(
    'test',
    '',
    time() + 60 * 60 * 2,
);

setcookie không có đối số được đặt tên

setcookie(
    name: 'test',
    expires: time() + 60 * 60 * 2,
);

setcookie với các đối số được đặt tên

Bên cạnh việc bỏ qua các đối số có giá trị mặc định, còn có lợi ích là biết rõ biến nào làm gì; thứ gì đó đặc biệt hữu ích trong các hàm có chữ ký phương thức lớn. Bây giờ chúng ta có thể nói rằng rất nhiều đối số thường có mùi mã; chúng ta vẫn phải đối phó với chúng bất kể thế nào đi chăng nữa, vì vậy thà có một cách làm lành mạnh hơn là không làm gì cả.

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.

# Đối số được đặt tên theo chiều sâu

Với những điều cơ bản đã sẵn sàng, chúng ta hãy xem những gì các đối số được đặt tên có thể và không thể làm được.

Trước hết, các đối số được đặt tên có thể được kết hợp với các đối số không được đặt tên – còn được gọi là các đối số có thứ tự. Trong trường hợp đó, các đối số được sắp xếp phải luôn được đặt trước.

Lấy ví dụ DTO của chúng tôi từ trước:

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

Bạn có thể xây dựng nó như vậy:

$data = new CustomerData(
    $input('name'),
    age: $input('age'),
    email: $input('email'),
);

Tuy nhiên, việc có một đối số có thứ tự sau một đối số được đặt tên sẽ gây ra lỗi:

$data = new CustomerData(
    age: $input('age'),
    $input('name'),
    email: $input('email'),
);

Tiếp theo, có thể sử dụng trải rộng mảng kết hợp với các đối số được đặt tên:

$input = (
    'age' => 25,
    'name' => 'Brent',
    'email' => '[email protected]',
);

$data = new CustomerData(...$input);

Nếu nhưtuy nhiên, thiếu các mục bắt buộc trong mảng hoặc nếu có một khóa không được liệt kê dưới dạng đối số được đặt tên thì sẽ xảy ra lỗi:

$input = (
    'age' => 25,
    'name' => 'Brent',
    'email' => '[email protected]',
    'unknownProperty' => 'This is not allowed',
);

$data = new CustomerData(...$input);

có thể kết hợp các đối số được đặt tên và sắp xếp trong một mảng đầu vào, nhưng chỉ khi các đối số được sắp xếp tuân theo quy tắc tương tự như trước: chúng phải đến trước!

$input = (
    'Brent',
    'age' => 25,
    'email' => '[email protected]',
);

$data = new CustomerData(...$input);


Nếu bạn đang sử dụng các hàm biến đổi, các đối số được đặt tên sẽ được chuyển cùng với tên khóa của chúng vào mảng đối số biến đổi. Lấy ví dụ sau:

class CustomerData
{
    public static function new(...$args): self
    {
        return new self(...$args);
    }

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

$data = CustomerData::new(
    email: '[email protected]',
    age: 25,
    name: 'Brent',
);

Trong trường hợp này, $args TRONG CustomerData::new sẽ chứa các dữ liệu sau:

(
    'age' => 25,
    'email' => '[email protected]',
    'name' => 'Brent',
)

Thuộc tính — còn được gọi là chú thích — cũng hỗ trợ các đối số được đặt tên:

class ProductSubscriber
{
    
    public function onProductCreated(ProductCreated $event) {  }
}

Không thể có một biến làm tên đối số:

$field = 'age';

$data = CustomerData::new(
    $field: 25,
);

Và cuối cùng, các đối số được đặt tên sẽ xử lý một cách thực tế các thay đổi về tên trong quá trình kế thừa. Lấy ví dụ này:

interface EventListener {
    public function on($event, $handler);
}

class MyListener implements EventListener
{
    public function on($myEvent, $myHandler)
    {
        
    }
}

PHP sẽ âm thầm cho phép thay đổi tên của $event ĐẾN $myEvent$handler ĐẾN $myHandler; Nhưng nếu bạn quyết định sử dụng các đối số được đặt tên bằng tên của cha mẹ thì điều đó sẽ dẫn đến lỗi thời gian chạy:

public function register(EventListener $listener)
{
    $listener->on(
        event: $this->event,
        handler: $this->handler, 
    );
}

Lỗi thời gian chạy trong trường hợp $listener là một ví dụ của MyListener

Cách tiếp cận thực dụng này được chọn để ngăn chặn sự thay đổi lớn khi tất cả các đối số được kế thừa sẽ phải giữ cùng tên. Có vẻ như là một giải pháp tốt cho tôi.


Đó là điều cần nói nhất về các đối số được đặt tên. Nếu bạn muốn biết thêm một chút câu chuyện đằng sau một số quyết định thiết kế, tôi khuyến khích bạn đọc RFC.

Bạn có mong muốn sử dụng các đối số được đặt tên không? 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