__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, даже если вы явно его не определяли.
Задание
ЛегкоДавайте создадим dynamic API-клиент, который использует magic methods для гибкой обработки вызовов методов. Вы создадите class, который перехватывает как вызовы методов instance, так и static, преобразуя их в содержательные ответы в стиле API без явного определения каждого метода.
Вы организуете код в двух файлах:
ApiClient.php: Создайте classApiClient, имитирующий взаимодействие с 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, идентификатор ресурса и значение. Создайте instanceApiClientс base URL. Затем выведите четыре строки:- Вызовите dynamic метод
get, используя идентификатор ресурса как суффикс имени метода (например, если ресурс — "Users", вызовитеgetUsers), передав значение как аргумент - Вызовите
getProductsс двумя аргументами:"electronics"и"active" - Вызовите static метод
createOrder, передав значение как аргумент - Вызовите static метод
deleteItem, передав идентификатор ресурса как аргумент
- Вызовите dynamic метод
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 в качестве аргумента
?>В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыКлючевое слово $thisМетодыСвойстваКонструктор (__construct)Деструктор (__destruct)Повторение — простой калькулятор4Наследование
Основы наследованияКлючевое слово parent::Переопределение методовКлючевое слово finalАбстрактные классыПовторение — иерархия сотрудников7Инкапсуляция
Public, Protected, PrivateМодификаторы доступа подробноГеттеры и сеттерыСокрытие информацииПродвижение конструктора (8.0)Повторение — система учёта студентов2Пространства имён и автозагрузка
Введение в пространства имёнКлючевое слово useСтандарт автозагрузки PSR-4Автозагрузчик ComposerПовторение — структурированный проект5Интерфейсы и контракты
Введение в интерфейсыРеализация интерфейсовРеализация нескольких интерфейсовИнтерфейс и абстрактный классАннотация типов с интерфейсамиПовторение — калькулятор фигур8Магические методы
Введение в магические методы__toString и __debugInfo__get, __set, __isset, __unset__call и __callStatic__clone и клонирование объектов__serialize и __unserializeПовторение — пользовательская коллекция3Свойства классов
Свойства экземпляра и статические свойстваКонстанты в классахСтатические методы и свойстваПриватные и защищённые свойстваСвойства только для чтения (PHP 8.1)Повторение — менеджер банковского счёта6Полиморфизм
Повторение переопределения методовПолиморфизм через интерфейсыАннотации типов и объединённые типыПозднее статическое связываниеПовторение — обработчик платежей9Трейты
Введение в трейтыИспользование нескольких трейтовРазрешение конфликтов трейтовАбстрактные методы в трейтахТрейты и наследование12Паттерны проектирования, часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн ObserverПаттерн StrategyПотренируйтесь самостоятельно: Онлайн-компилятор PHP