__call и __callStatic
Часть раздела Объектно-ориентированное программирование путешествия по PHP на Coddy — урок 47 из 91.
Подобно тому, как __get() и __set() перехватывают доступ к свойствам, методы __call() и __callStatic() перехватывают вызовы методов. Они срабатывают, когда вы вызываете метод, который не существует или недоступен в объекте или классе.
Метод __call() обрабатывает вызовы методов экземпляра. Он получает имя метода и массив аргументов:
<?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Эти магические методы предоставляют мощные возможности для создания fluent API, реализации пересылки методов или построения динамических конструкторов запросов, где имена методов преобразуются в операции базы данных. Они позволяют вашим объектам интеллектуально реагировать на любые вызовы методов, даже на те, которые не были определены явно.
Задание
ЛегкоДавайте создадим динамический API-клиент, который использует магические методы для гибкой обработки вызовов методов. Вы создадите класс, который перехватывает вызовы как обычных, так и статических методов, преобразуя их в осмысленные API-подобные ответы без явного определения каждого метода.
Вы организуете свой код в двух файлах:
ApiClient.php— Создайте классApiClient, который имитирует взаимодействие с API с помощью магических методов. Ваш класс должен иметь приватное свойство$baseUrl, устанавливаемое через конструктор. Реализуйте два магических метода:__call()— Обрабатывает вызовы методов экземпляра. Когда вызывается метод, начинающийся сget(например,getUsersилиgetPosts), извлеките имя ресурса (часть после "get") и верните"GET [baseUrl]/[resource]: [arguments joined by comma]". Имя ресурса должно быть преобразовано в нижний регистр. Если метод не начинается с "get", верните"Unknown action: [methodName]".__callStatic()— Обрабатывает вызовы статических методов. Когда вызывается метод, начинающийся сcreate(например,createUser), извлеките имя ресурса и верните"POST /[resource]: [arguments joined by comma]". Имя ресурса должно быть в нижнем регистре. Для методов, начинающихся сdelete, верните"DELETE /[resource]: [first argument]". Для любого другого метода верните"Static action not supported: [methodName]".
main.php— Подключите файл ApiClient. Вы получите три входных значения: базовый URL, идентификатор ресурса и значение. Создайте экземплярApiClientс базовым URL. Затем выведите четыре строки:- Вызовите динамический метод
get, используя идентификатор ресурса в качестве суффикса имени метода (например, если ресурс — "Users", вызовитеgetUsers) со значением в качестве аргумента - Вызовите
getProductsс двумя аргументами:"electronics"и"active" - Вызовите статический метод
createOrderсо значением в качестве аргумента - Вызовите статический метод
deleteItemс идентификатором ресурса в качестве аргумента
- Вызовите динамический метод
Магические методы позволяют вашему API-клиенту динамически реагировать на любой вызов метода. Вместо того чтобы определять getUsers(), getPosts(), getProducts() и десятки других, один метод __call() обрабатывает их все, анализируя имя метода и извлекая соответствующую информацию.
Шпаргалка
Метод __call() перехватывает вызовы методов экземпляра, которые не существуют или недоступны. Он получает имя метода и массив аргументов:
<?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
Эти магические методы полезны для создания текучих интерфейсов (fluent APIs), реализации перенаправления методов или создания динамических построителей запросов, где имена методов преобразуются в операции.
Попробуйте сами
<?php
require_once 'ApiClient.php';
// Чтение входных данных
$baseUrl = trim(fgets(STDIN));
$resource = trim(fgets(STDIN));
$value = trim(fgets(STDIN));
// TODO: Создайте экземпляр ApiClient с базовым URL
// TODO: Вызовите динамический метод get, используя ресурс в качестве суффикса имени метода
// Подсказка: Используйте переменные вызовы методов, например $api->{"get" . $resource}($value)
// TODO: Вызовите getProducts с двумя аргументами: "electronics" и "active"
// TODO: Вызовите статический метод createOrder, используя значение в качестве аргумента
// Подсказка: Используйте ApiClient::createOrder($value)
// TODO: Вызовите статический метод deleteItem, используя ресурс в качестве аргумента
?>В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыКлючевое слово $thisМетодыСвойстваКонструктор (__construct)Деструктор (__destruct)Итоги — Простой калькулятор4Наследование
Основы наследованияКлючевое слово parent::Переопределение методовКлючевое слово finalАбстрактные классыИтоги — Иерархия сотрудников7Инкапсуляция
Public, Protected, PrivateПодробный разбор модификаторов доступаГеттеры и сеттерыСокрытие данныхConstructor Promotion (8.0)Итоги — Система учета студентов10Продвинутые концепции ООП
Композиция против наследованияВнедрение зависимостейАнонимные классыПеречисления (PHP 8.1)Файберы (PHP 8.1)Глубокое погружение в клонирование объектовГенераторы и итераторы13Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикПаттерн Репозиторий2Пространства имен и автозагрузка
Введение в пространства именКлючевое слово useСтандарт автозагрузки PSR-4Автозагрузчик ComposerИтоги: структурированный проект5Интерфейсы и контракты
Введение в интерфейсыРеализация интерфейсовРеализация нескольких интерфейсовИнтерфейс против абстрактного классаType Hinting с интерфейсамиИтоги — Калькулятор фигур8Магические методы
Введение в магические методы__toString и __debugInfo__get, __set, __isset, __unset__call и __callStatic__clone и клонирование объектов__serialize и __unserializeИтоги — Кастомная коллекция11Система типов и обработка ошибок
Объявление типовNullable-типыТипы объединения и пересеченияКлассы исключенийИерархия пользовательских исключенийTry, Catch, FinallyИтоги — Валидатор форм14Проект: Управление библиотекой
Обзор проектаКлассы Book и User3Свойства классов
Свойства экземпляра и статические свойстваКонстанты в классахСтатические методы и свойстваПриватные и защищенные свойстваСвойства Readonly (PHP 8.1)Итоги — Менеджер банковского счета6Полиморфизм
Снова о переопределении методовПолиморфизм через интерфейсыType Hinting и Union TypesПозднее статическое связываниеИтоги — Payment Processor9Трейты
Введение в трейтыИспользование нескольких трейтовРазрешение конфликтов трейтовАбстрактные методы в трейтахТрейты и наследование12Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн ObserverПаттерн Strategy