Вызываемое выражение — ссылка на функцию или метод, которая передаётся в другую функцию как аргумент. Параметрам, которые принимают вызываемые выражения, объявляют тип callable.
<?php
function foo(callable $callback) {
$callback();
}Отдельные функции наподобие array_map(), usort() или preg_replace_callback() принимают callback-функции как аргументы.
Тип callable представляет значения или выражения, доступные для вызова как функция. Вызываемые выражения вызывают как функции или передают как аргументы в функции или методы, которые ожидают в параметре callback-функцию. Свойствам классов нельзя объявлять тип callable; вызываемым свойствам объявляют тип Closure.
Вызываемыми значениями становятся:
Объекты Closure создают синтаксисом анонимных функций, стрелочных функций, синтаксисом первоклассных вызываемых значений или методом Closure::fromCallable().
Замечание: Синтаксис первоклассных callable-значений доступен только с PHP 8.1.0.
Пример #1 Пример объявления функций обратного вызова, которые становятся объектами класса Closure
<?php
// Синтаксис анонимных функций
$double1 = function ($a) {
return $a * 2;
};
// Синтаксис первоклассных вызываемых значений
function double_function($a) {
return $a * 2;
}
$double2 = double_function(...);
// Синтаксис стрелочных функций
$double3 = fn($a) => $a * 2;
// Метод Closure::fromCallable
$double4 = Closure::fromCallable('double_function');
// Вызов замыкания как callback-функции
// удваивает значение каждого элемента в диапазоне
$new_numbers = array_map($double1, range(1, 5));
print implode(' ', $new_numbers) . PHP_EOL;
$new_numbers = array_map($double2, range(1, 5));
print implode(' ', $new_numbers) . PHP_EOL;
$new_numbers = array_map($double3, range(1, 5));
print implode(' ', $new_numbers) . PHP_EOL;
$new_numbers = array_map($double4, range(1, 5));
print implode(' ', $new_numbers);Результат выполнения приведённого примера в PHP 8.1:
2 4 6 8 10 2 4 6 8 10 2 4 6 8 10 2 4 6 8 10
Вызываемые выражения объявляют как строку с названием функции или статического метода. PHP поддерживает передачу встроенных и пользовательских функций, но не языковых конструкций: array(), echo, empty(), eval(), isset(), list(), print или unset().
Для ссылки на статический метод класса не потребуется создавать
объект (object) этого класса, достаточно создать массив
с названием класса в элементе с индексом 0 и названием метода в элементе с индексом 1
или сослаться на метод через синтаксис с оператором ::, который разрешает
область действия метода:
'ClassName::methodName'.
На методы объектов (object) в вызываемых выражениях ссылаются через массив: объект (object) указывают в элементе с индексом 0, а название метода — в элементе с индексом 1.
Видимость метода в объектах Closure проверяется относительно места объявления, а не вызова замыкания Closure, тогда как видимость методов в выражениях с псевдотипом callable проверяется относительно места вызова выражения, поэтому попытка вызова callable-выражения, которое ссылается на недоступный в точке вызова метод, выдаст ошибку. На методы классов лучше ссылаться через замыкания Closure, поскольку видимость метода в точке вызова замыкания не влияет на доступность вызова метода.
Замечание: Объекты Closure связываются с областью видимости объявления, тогда как вызываемые выражения со ссылкой на метод класса через строку или массив разрешаются в области видимости вызова. Вызываемое значение со ссылкой на закрытый или защищённый метод класса, который потребуется вызывать извне области видимости класса, создают методом Closure::fromCallable() или синтаксисом первоклассных вызываемых значений.
PHP поддерживает вызываемые выражения, которые возможно передать как аргумент,
но невозможно вызывать.
К таким выражениям относятся вызываемые значения, которые зависят от контекста и ссылаются на метод класса
в иерархии наследования через ключевые слова:
'parent::method' или ["static", "method"].
Замечание: С PHP 8.2.0 контекстно-зависимые вызываемые выражения устарели. Независимые от контекста ссылки на методы получают путём замены выражений наподобие
'parent::method'выражениямиparent::class . '::method'или синтаксисом первоклассных вызываемых значений.
Пример #2 Примеры вызова callable-выражений функцией call_user_function()
<?php
// Пример callback-функции
function my_callback_function()
{
echo "Привет, мир!", PHP_EOL;
}
// Пример callback-метода
class MyClass
{
static function myCallbackMethod()
{
echo "Привет, мир!", PHP_EOL;
}
}
// Тип 1: Простой вызов callback-функции
call_user_func('my_callback_function');
// Тип 2: Вызов статического метода класса
call_user_func(['MyClass', 'myCallbackMethod']);
// Тип 3: Вызов метода объекта класса
$obj = new MyClass();
call_user_func([$obj, 'myCallbackMethod']);
// Тип 4: Вызов статического метода класса
call_user_func('MyClass::myCallbackMethod');
// Тип 5: Вызов статического метода класса с разрешением названия класса через языковую конструкцию ::class
call_user_func([MyClass::class, 'myCallbackMethod']);
// Тип 6: Вызов статического метода класса по контекстно-зависимой относительной ссылке
class A
{
public static function who()
{
echo 'A', PHP_EOL;
}
}
class B extends A
{
public static function who()
{
echo 'B', PHP_EOL;
}
}
call_user_func(['B', 'parent::who']); // Выводит: A.
// Начиная с PHP 8.2.0 callable-выражения
// с относительными названиями методов устарели
// Тип 7: Объекты, классы которых реализуют магический метод __invoke(),
// доступны для вызова как функции
class C
{
public function __invoke($name)
{
echo 'Привет, ', $name;
}
}
$c = new C();
call_user_func($c, 'PHP!');Результат выполнения приведённого примера:
Привет, мир! Привет, мир! Привет, мир! Привет, мир! Привет, мир! Deprecated: Callables of the form ["B", "parent::who"] are deprecated in script on line 51 A Привет, PHP!
Замечание:
Callback-функции, которые зарегистрировали функцией call_user_func() или call_user_func_array(), не вызовутся при непойманном исключении, которое выбросила предыдущая callback-функция.