Menu
Coddy logo textTech

__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, реализации пересылки методов или построения динамических конструкторов запросов, где имена методов преобразуются в операции базы данных. Они позволяют вашим объектам интеллектуально реагировать на любые вызовы методов, даже на те, которые не были определены явно.

challenge icon

Задание

Легко

Давайте создадим динамический 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, используя ресурс в качестве аргумента

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

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

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