Menu
CoddyTech

__call và __callStatic

Thuộc phần Lập trình hướng đối tượng trong hành trình PHP của Coddy. Bài học 47 trên 91.

Tương tự như __get() và __set() chặn thao tác truy cập thuộc tính, các phương thức __call() và __callStatic() chặn lời gọi phương thức. Chúng được kích hoạt khi bạn gọi một phương thức không tồn tại hoặc không thể truy cập trên một đối tượng hoặc lớp.

Phương thức __call() xử lý các lệnh gọi phương thức của đối tượng. Phương thức này nhận tên phương thức và một mảng đối số:

<?php
class Messenger {
    public function __call(string $name, array $arguments): string {
        return "Called '$name' with: " . implode(", ", $arguments);
    }
}

$msg = new Messenger();
echo $msg->sendEmail("Hello", "World");

Đầu ra:

Called 'sendEmail' with: Hello, World

Để gọi phương thức tĩnh, hãy dùng __callStatic(). Lưu ý, bạn phải khai báo phương thức này là static:

<?php
class QueryBuilder {
    public static function __callStatic(string $name, array $arguments): string {
        if (str_starts_with($name, "findBy")) {
            $field = substr($name, 6);
            return "Finding by $field: " . $arguments[0];
        }
        return "Unknown method: $name";
    }
}

echo QueryBuilder::findByEmail("test@example.com");

Đầu ra:

Finding by Email: test@example.com

Các phương thức ma thuật rất hữu ích khi tạo API linh hoạt, triển khai tính năng chuyển tiếp phương thức hoặc xây dựng trình tạo truy vấn động, trong đó tên phương thức được chuyển thành các thao tác cơ sở dữ liệu. Chúng cho phép đối tượng phản hồi thông minh với mọi lời gọi phương thức, kể cả những phương thức bạn chưa định nghĩa rõ ràng.

challenge icon

Thử thách

Dễ

Hãy cùng xây dựng một API client linh hoạt, sử dụng các phương thức ma thuật để xử lý lời gọi phương thức. Bạn sẽ tạo một lớp chặn cả lời gọi phương thức của đối tượng lẫn lời gọi phương thức tĩnh, rồi chuyển chúng thành các phản hồi giống API có ý nghĩa mà không cần định nghĩa từng phương thức riêng.

Bạn sẽ sắp xếp code trong hai tệp:

  • ApiClient.php: Tạo lớp ApiClient mô phỏng các tương tác API bằng phương thức ma thuật. Lớp của bạn cần có thuộc tính $baseUrl riêng, được thiết lập thông qua hàm khởi tạo. Hãy triển khai hai phương thức ma thuật:
    • __call(): Xử lý lời gọi phương thức của đối tượng. Khi có lời gọi phương thức bắt đầu bằng get (chẳng hạn getUsers hoặc getPosts), hãy trích xuất tên tài nguyên (phần sau "get") và trả về "GET [baseUrl]/[resource]: [arguments joined by comma]". Tên tài nguyên cần được chuyển thành chữ thường. Nếu phương thức không bắt đầu bằng "get", hãy trả về "Unknown action: [methodName]".
    • __callStatic(): Xử lý lời gọi phương thức tĩnh. Khi có lời gọi phương thức bắt đầu bằng create (chẳng hạn createUser), hãy trích xuất tên tài nguyên và trả về "POST /[resource]: [arguments joined by comma]". Tên tài nguyên cần viết bằng chữ thường. Với các phương thức bắt đầu bằng delete, hãy trả về "DELETE /[resource]: [first argument]". Với mọi phương thức khác, hãy trả về "Static action not supported: [methodName]".
  • main.php: Nạp tệp ApiClient. Bạn sẽ nhận ba đầu vào: URL cơ sở, mã định danh tài nguyên và một giá trị. Tạo một đối tượng ApiClient bằng URL cơ sở. Sau đó, in ra bốn dòng:
    • Gọi một phương thức get động, dùng mã định danh tài nguyên làm hậu tố tên phương thức (ví dụ: nếu tài nguyên là "Users", hãy gọi getUsers) và dùng giá trị làm đối số
    • Gọi getProducts với hai đối số: "electronics" và "active"
    • Gọi phương thức tĩnh createOrder với giá trị làm đối số
    • Gọi phương thức tĩnh deleteItem với mã định danh tài nguyên làm đối số

Phương thức ma thuật cho phép API client phản hồi linh hoạt với mọi lời gọi phương thức. Thay vì định nghĩa getUsers(), getPosts(), getProducts() và hàng chục phương thức khác, chỉ một phương thức __call() có thể xử lý tất cả bằng cách kiểm tra tên phương thức và trích xuất thông tin liên quan.

Tự làm thử

<?php

require_once 'ApiClient.php';

// Đọc dữ liệu đầu vào
$baseUrl = trim(fgets(STDIN));
$resource = trim(fgets(STDIN));
$value = trim(fgets(STDIN));

// TODO: Tạo một instance ApiClient với URL cơ sở

// TODO: Gọi phương thức get động, dùng resource làm hậu tố tên phương thức
// Gợi ý: Dùng cách gọi phương thức qua biến như $api->{"get" . $resource}($value)

// TODO: Gọi getProducts với hai đối số: "electronics" và "active"

// TODO: Gọi phương thức tĩnh createOrder với value làm đối số
// Gợi ý: Dùng ApiClient::createOrder($value)

// TODO: Gọi phương thức tĩnh deleteItem với resource làm đối số

?>
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch PHP online