callable php что такое
Callable php что такое
Передача
Метод созданного объекта ( object ) передаётся как массив, содержащий объект по индексу 0 и имя метода по индексу 1. Доступ к закрытым и защищённым методам разрешён изнутри класса.
Помимо обычных пользовательских функций, в качестве callback-функции можно передавать анонимные функции и стрелочные функции.
Как правило, любой объект, реализующий __invoke(), также может быть передан в параметр callback.
Пример #1 Пример callback-функции
// Пример callback-функции
function my_callback_function () <
echo ‘Привет, мир!’ ;
>
// Пример callback-метода
class MyClass <
static function myCallbackMethod () <
echo ‘Привет, мир!’ ;
>
>
// Тип 1: Простой callback
call_user_func ( ‘my_callback_function’ );
// Тип 4: Вызов статического метода класса
call_user_func ( ‘MyClass::myCallbackMethod’ );
// Тип 5: Вызов относительного статического метода
class A <
public static function who () <
echo «A\n» ;
>
>
class B extends A <
public static function who () <
echo «B\n» ;
>
>
Пример #2 Пример callback-функции с использованием замыкания
Результат выполнения данного примера:
User Contributed Notes 17 notes
When specifying a call back in array notation (ie. array($this, «myfunc») ) the method can be private if called from inside the class, but if you call it from outside you’ll get a warning:
Warning: array_walk() expects parameter 2 to be a valid callback, cannot access private method mc::walkIt() in /in/tfh7f on line 22
— Using the name of a function as string has worked since at least 4.3.0
— Calling anonymous functions and invokable objects has worked since 5.3.0
— Using the array structure [$object, ‘method’] has worked since 5.4.0
Note, however, that the following are not supported when calling callbacks as variable functions, even though they are supported by call_user_func():
— Calling static class methods via strings such as ‘foo::doStuff’
— Calling parent method using the [$object, ‘parent::method’] array structure
All of these cases are correctly recognized as callbacks by the ‘callable’ type hint, however. Thus, the following code will produce an error «Fatal error: Call to undefined function foo::doStuff() in /tmp/code.php on line 4»:
static function doStuff () <
echo «Hello World!» ;
>
>
foo :: callIt ( ‘foo::doStuff’ );
?>
The code would work fine, if we replaced the ‘$callback()’ with ‘call_user_func($callback)’ or if we used the array [‘foo’, ‘doStuff’] as the callback instead.
You can use ‘self::methodName’ as a callable, but this is dangerous. Consider this example:
class Foo <
public static function doAwesomeThings () <
FunctionCaller :: callIt ( ‘self::someAwesomeMethod’ );
>
public static function someAwesomeMethod () <
// fantastic code goes here.
>
>
Foo :: doAwesomeThings ();
?>
This results in an error:
Warning: class ‘FunctionCaller’ does not have a method ‘someAwesomeMethod’.
For this reason you should always use the full class name:
:: callIt ( ‘Foo::someAwesomeMethod’ );
?>
I believe this is because there is no way for FunctionCaller to know that the string ‘self’ at one point referred to to `Foo`.
> As of PHP 5.2.3, it is also possible to pass ‘ClassName::methodName’
You can also use ‘self::methodName’. This works in PHP 5.2.12 for me.
If you pass a callable method to a function with a callable type declaration, the error message is misleading:
class X <
protected function foo (): void <>
>
I needed a function that would determine the type of callable being passed, and, eventually,
normalized it to some extent. Here’s what I came up with:
?>
Hope someone else finds it useful.
Применение замыканий в PHP
Введение в PHP 5.3 замыканий — одно из главных его новшеств и хотя после релиза прошло уже несколько лет, до сих пор не сложилось стандартной практики использования этой возможности языка. В этой статье я попробовал собрать все наиболее интересные возможности по применению замыканий в PHP.
Для начала рассмотрим, что же это такое — замыкание и в чем его особенности в PHP.
Как видим, замыкание как и лямбда-функция представляют собой объект класса Closure, коорый хранит переданные параметры. Для того, чтобы вызывать объект как функцию, в PHP5.3 ввели магический метод __invoke.
Используя конструкцию use мы наследуем переменную из родительской области видимости в локальную область видимости ламбда-функции.
Ситаксис прост и понятен. Не совсем понятно применение такого функционала в разработке web-приложений. Я просмотрел код нескольких совеременных фреймворков, использующих новые возможности языка и попытался собрать вместе их различные применения.
Функции обратного вызова
Самое очевидное применение анонимных функций — использование их в качестве функций обратного вызова (callbacks). В PHP имеется множество стандартных функций, принимающих на вход тип callback или его синоним callable введенный в PHP 5.4. Самые популярные из них array_filter, array_map, array_reduce. Функция array_map служит для итеративной обработки элементов массива. Callback-функция применяется к каждому элементу массива и в качестве результата выдается обработанный массив. У меня сразу возникло желание сравнить производительность обычной обработки массива в цикле с применением встроенной функции. Давайте поэкспериментируем.
Как видно, накладные расходы на большое количество вызовов функций дают ощутимый спад в производительности, чего и следовало ожидать. Хотя тест синтетический, задача обработки больших массивов возникает часто, и в данном случае применение функций обработки данных может стать тем местом, которе будет существенно тормозить ваше приложение. Будьте осторожны. Тем не менее в современных приложениях такой подход используется очень часто. Он позволяет делать код более лаконичным, особенно, если обработчик объявляется где-то в другом месте, а не при вызове.
По сути в данном контексте применение анонимных функций ничем не отличается от старого способа передачи строкового имени функции или callback-массива за исключением одной особенности — теперь мы можем использовать замыкания, то есть сохранять переменные из области видимости при создании функции. Рассмотрим пример обработки массива данных перед добавлением их в базу данных.
Очень удобно применять анонимные функции и для фильтрации
События.
Замыкания идеально подходят в качестве обработчиков событий. Например
Вынос логики в обработчики событий с одной стороны делает код более чистым, с другой стороны — усложняет поиск ошибок — поведение системы иногда становится неожиданным для человека, который не знает, какие обработчики навешаны в данный момент.
Валидация
Замыкания по сути сохраняют некоторую логику в переменной, которая может быть выполнена или не выполнена в по ходу работы скрипта. Это то, что нужно для реализации валидаторов:
В последнем случае мы применяем функцию высшего порядка, которая возвращает другую функцию — валидатор с предустановленными границами значений. Применять валидаторы можно, например, так.
Использование в формах классический пример. Также валидация может использоваться в сеттерах и геттерах обычных классов, моделях и т.д. Хорошим тоном, правда, считается декларативная валидация, когда правила описаны не в форме функций, а в форме правил при конфигурации, тем не менее, иногда такой подход очень кстати.
Выражения
В Symfony встречается очень интересное применение замыканий. Класс ExprBuilder опеделяет сущность, которая позволяет строить выражения вида
В Symfony как я понял это внутренний класс, который используется для создания обработки вложенных конфигурационных массивов (поправьте меня, если не прав). Интересна идея реализации выражений в виде цепочек. В принципе вполне можно реализовать класс, который бы описывал выражения в таком виде:
Применение, конечно, экспериментально. По сути — это запись некоторого алгоритма. Реализация такого функционала достаточно сложна — выражение в идеальном случае должно хранить дерево операций. Инетересна концепция, может быть где-то такая конструкция будет полезна.
Роутинг
Во многих мини-фреймворках роутинг сейчас работает на анонимных функциях.
Достаточно удобно и лаконично.
Кеширование
На хабре это уже обсуждалось, тем не менее.
Здесь метод get проверяет валидность кеша по ключу ‘users.list’ и если он не валиден, то обращается к функции за данными. Третий параметр определяет длительность хранения данных.
Инициализация по требованию
Допустим, у нас есть сервис Mailer, который мы вызываем в некоторых методах. Перед использованием он должен быть сконфигурирован. Чтобы не инициализировать его каждый раз, будем использовать ленивое создание объекта.
Инициализация объекта произойдет только перед самым первым использованием.
Изменение поведения объектов
Иногда бывает полезно переопределить поведение объектов в процессе выполнения скрипта — добавить метод, переопределить старый, и т.д. Замыкание поможет нам и здесь. В PHP5.3 для этого нужно было использовать различные обходные пути.
В принципе можно и переопределять старый метод, однако только в случае если он был определен подобным путем. Не совсем удобно. Поэтому в PHP 5.4 появилось возможность связать замыкание с объектом.
Конечно, модификации объекта не получилось, тем не менее замыкание получает доступ к приватным функциям и свойствам.
Передача как параметры по умолчанию в методы доступа к данным
Пример получения значения из массива GET. В случае его отсутствия значение будет получено путем вызова функции.
Функции высшего порядка
Здесь уже был пример создания валидатора. Приведу пример из фреймворка lithium
Метод возвращает замыкание, которое может быть использовано потом для записи сообщения в кеш.
Передача в шаблоны
Иногда в шаблон удобно передавать не просто данные, а, например, сконфигурированную функцию, которую можно вызвать из кода шаблона для получения каких либо значений.
В данном случае в шаблоне генерировалось несколько ссылок на сущности пользователя и в адресах этих ссылок фигурировал его логин.
Рекурсивное определение замыкания
Напоследок о том, как можно задавать рекурсивные замыкания. Для этого нужно передавать в use ссылку на замыкание, и вызывать ее в коде. Не забывайте об условии прекращения рекурсии
Многие из примеров выглядят натянуто. Сколько лет жили без них — и ничего. Тем не менее иногда применение замыкания достаточно естественно и для PHP. Умелое использование этой возможности позволит сделать код более читаемым и увеличить эффективность работы программиста. Просто нужно немного подстроить свое мышление под новую парадигму и все станет на свои места. А вообще рекомендую сравнить, как используются такие вещи в других языках типа Python. Надеюсь, что кто-нибудь нашел для себя здесь что-то новое. И конечно, если кто-то знает еще какие-нибудь интересные применения замыканий, то очень жду ваши комментарии. Спасибо!
is_callable
(PHP 4 >= 4.0.6, PHP 5, PHP 7, PHP 8)
is_callable — Проверяет, что значение может быть вызвано как функция в текущей области видимости
Описание
Список параметров
Значение для проверки
Получает «вызываемое имя». В примере ниже это «someClass::someMethod». Следует иметь в виду, что хотя запись someClass::SomeMethod() означает вызываемый статический метод, это не так.
Возвращаемые значения
Примеры
Пример #1 Пример использования is_callable()
// Как проверить переменную, чтобы узнать, может ли она быть вызвана
// как функция.
//
// Простая переменная, содержащая имя функции
//
//
// Массив, содержащий метод класса
//
$anObject = new someClass ();
Пример #2 is_callable() и конструкторы
Функция is_callable() не считает конструкторы за callable.
class Foo
<
public function __construct () <>
public function foo () <>
>
Результат выполнения данного примера:
Примечания
Смотрите также
User Contributed Notes 6 notes
If the target class has __call() magic function implemented, then is_callable will ALWAYS return TRUE for whatever method you call it.
is_callable does not evaluate your internal logic inside __call() implementation (and this is for good).
Therefore every method name is callable for such classes.
Hence it is WRONG to say (as someone said):
. is_callable will correctly determine the existence of methods made with __call.
Example:
class TestCallable
<
public function testing ()
<
return «I am called.» ;
>
class Test
<
public function method1 () < >
public static function method2 () < >
>
is_callable generates an [E_STRICT] error if the tested method cannot be called staticly. (and returns the good value)
I used @is_called
i’m using php 5.2.1
The story about __call() is a bit more complicated unfortunately. It will always return true ONLY if you pass an instance of a class, not if you pass the class name itself:
is_callable ([ MyClass ::class, ‘method’ ]); // true
is_callable ([new MyClass (), ‘method’ ]); // true
is_callable ([ MyClass ::class, ‘other’ ]); // false.
is_callable ([new MyClass (), ‘other’ ])); // true
Note that, for the purpose of this function, an abstract method, although necessarily non-callable since it does not have a body, is still considered to be callable:
abstract class Foo <
abstract function bar ();
>
is_callable() does _not_ check wheter this function is disabled by php.ini’s disable_functions
Callbacks / Callables
Callbacks can be denoted by callable type hint as of PHP 5.4. This documentation used callback type information for the same purpose.
Some functions like call_user_func() or usort() accept user-defined callback functions as a parameter. Callback functions can not only be simple functions, but also object methods, including static class methods.
Passing
A method of an instantiated object is passed as an array containing an object at index 0 and the method name at index 1. Accessing protected and private methods from within a class is allowed.
Static class methods can also be passed without instantiating an object of that class by passing the class name instead of an object at index 0. As of PHP 5.2.3, it is also possible to pass ‘ClassName::methodName’.
Apart from common user-defined function, anonymous functions can also be passed to a callback parameter.
Пример #1 Callback function examples
// An example callback function
function my_callback_function () <
echo ‘hello world!’ ;
>
// An example callback method
class MyClass <
static function myCallbackMethod () <
echo ‘Hello World!’ ;
>
>
// Type 1: Simple callback
call_user_func ( ‘my_callback_function’ );
// Type 4: Static class method call (As of PHP 5.2.3)
call_user_func ( ‘MyClass::myCallbackMethod’ );
// Type 5: Relative static class method call (As of PHP 5.3.0)
class A <
public static function who () <
echo «A\n» ;
>
>
class B extends A <
public static function who () <
echo «B\n» ;
>
>
Пример #2 Callback example using a Closure
Результат выполнения данного примера:
Замыкания в PHP
или в PHP — это обычные функции, но без имени. Давайте рассмотрим пример такой функции:
В этом примере есть анонимная функция, но нет никакого смысла. Возникает вопрос — как использовать такие функции? Следующий пример поможет разобраться в этом:
Но этот пример не особо удобный для использования, ведь можно и простые функции использованть.
Как на практике используются замыкания
Обычно анонимные функции или замыкания в PHP используются чтобы передать их в качестве параметров другой функции. В PHP есть несколько встроенных функций, которые в качестве аргумента принимают замыкание, но об этом будет написано ниже.
Давайте ещё усложним наш пример.
Функция is_callable()
Анонимные функции в PHP реализованы с помощью встроенного класса Closure (PHP 5 >= 5.3.0, PHP 7). То есть каждая анонимная функция является объектом этого класса.
Конструкция use
При помощи ключевого слова use анонимной функции можно передать несколько переменных, они перечесляются в круглых скобках через запятую.
Также важно понимать, что конструкция use делает видимой именно переменные из родительской области видимости, а это не то же самое что и переменные из глобальной области видимости. Глобальная область видимости не меняется со сменой исполнения функций различной степени вложенности.
Аргументы в анонимных функциях
В анонимную функцию можно передать аргументы. Давайте для примера передадим один аргумент в нашу функцию.
С аргументами всё очень просто, тут анонимные функции ничем не отличаются от обычных.
Функция preg_replace_callback
Я обещал несколько встроенных в PHP функций, которые принимают в качестве аргумента замыкание, вот одна из них: preg_replace_callback
preg_replace_callback — выполняет поиск по регулярному выражению и замену с использованием callback-функции (замыкания).
Это краткий синтаксис, подробнее про возможности этой функции можно почитать на сайте мануала по PHP.
Функция call_user_func
Функция call_user_func — вызывает пользовательскую функцию, указанную в первом параметре. Возвращает результат функции, или FALSE в случае ошибки.
Примеры использования call_user_func :
Пример использования call_user_func в ООП.
Класс Closure
Также отмечу, что при вызове объекта как функции, вызывается магический метод __invoke (начиная с PHP5.3).