Menu
Coddy logo textTech

__call и __callStatic

Часть раздела Объектно-ориентированное программирование путешествия по PHP на Coddy. Урок 47 из 91.

Подобно тому как __get() и __set() перехватывают доступ к свойствам, методы __call() и __callStatic() перехватывают вызовы методов. Они срабатывают, когда вы вызываете метод, который не существует или недоступен в объекте или class.

method __call() обрабатывает вызовы instance method. Он получает имя method и array arguments:

<?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");

Вывод:

Called 'sendEmail' with: Hello, World

Для вызовов статических методов используйте __callStatic(). Обратите внимание: он должен быть объявлен как 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");

Вывод:

Finding by Email: test@example.com

Эти magic-методы отлично подходят для создания fluent API, реализации переадресации method или построения dynamic-конструкторов запросов, где имена method преобразуются в операции с базой данных. Они позволяют вашим объектам разумно реагировать на любой вызов method, даже если вы явно его не определяли.

challenge icon

Задание

Легко

Давайте создадим dynamic API-клиент, который использует magic methods для гибкой обработки вызовов методов. Вы создадите class, который перехватывает как вызовы методов instance, так и static, преобразуя их в содержательные ответы в стиле API без явного определения каждого метода.

Вы организуете код в двух файлах:

  • ApiClient.php: Создайте class ApiClient, имитирующий взаимодействие с API с помощью magic methods. В вашем class должно быть private свойство $baseUrl, устанавливаемое через конструктор. Implement два magic methods:
    • __call(): Обрабатывает вызовы методов instance. Когда вызывается метод, начинающийся с get (например, getUsers или getPosts), extract имя ресурса (часть после "get") и верните "GET [baseUrl]/[resource]: [arguments joined by comma]". Имя ресурса следует преобразовать в lowercase. Если метод doesn’t начинаться с "get", верните "Unknown action: [methodName]".
    • __callStatic(): Обрабатывает вызовы static методов. Когда вызывается метод, начинающийся с create (например, createUser), extract имя ресурса и верните "POST /[resource]: [arguments joined by comma]". Имя ресурса должно быть lowercase. Для методов, начинающихся с delete, верните "DELETE /[resource]: [first argument]". Для любого другого метода верните "Static action not supported: [methodName]".
  • main.php: Подключите файл ApiClient. Вы получите три inputs: base URL, идентификатор ресурса и значение. Создайте instance ApiClient с base URL. Затем выведите четыре строки:
    • Вызовите dynamic метод get, используя идентификатор ресурса как суффикс имени метода (например, если ресурс — "Users", вызовите getUsers), передав значение как аргумент
    • Вызовите getProducts с двумя аргументами: "electronics" и "active"
    • Вызовите static метод createOrder, передав значение как аргумент
    • Вызовите static метод deleteItem, передав идентификатор ресурса как аргумент

Magic methods позволяют вашему API-клиенту dynamic отвечать на любой вызов метода. Вместо определения getUsers(), getPosts(), getProducts() и десятков других методов один метод __call() обрабатывает их все, анализируя имя метода и извлекая нужную информацию.

Попробуйте сами

<?php

require_once 'ApiClient.php';

// Чтение входных данных
$baseUrl = trim(fgets(STDIN));
$resource = trim(fgets(STDIN));
$value = trim(fgets(STDIN));

// TODO: Создать экземпляр ApiClient с базовым URL

// TODO: Вызвать динамический метод get, используя resource как суффикс имени метода
// Подсказка: Используйте вызовы переменных методов вроде $api->{"get" . $resource}($value)

// TODO: Вызвать getProducts с двумя аргументами: "electronics" и "active"

// TODO: Вызвать статический метод createOrder с value в качестве аргумента
// Подсказка: Используйте ApiClient::createOrder($value)

// TODO: Вызвать статический метод deleteItem с resource в качестве аргумента

?>
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор PHP