Вызываемое выражение — ссылка на функцию или метод, которая передаётся
в другую функцию как аргумент.
Параметрам, которые принимают вызываемые выражения, объявляют тип callable.
Объявление вызываемых выражений
Тип callable представляет значения или выражения, доступные для вызова как функция.
Вызываемые выражения вызывают как функции или передают как аргументы в функции или методы,
которые ожидают в параметре callback-функцию.
Свойствам классов нельзя объявлять тип callable;
вызываемым свойствам объявляют тип Closure.
Вызываемыми значениями становятся:
-
Объекты класса Closure
-
Строки (string) с названием функции или квалифицированным названием метода
-
Массивы (array) с названием класса или объектом (object)
в элементе с индексом 0 и названием метода в элементе с индексом 1
-
Объекты (object), в классе которых объявили магический метод
__invoke()
Объекты 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-функция.