Функцию можно присвоить переменной, так же как и обычное значение. Для этого имя функции должно быть присвоено переменной в виде строки, но без указания круглых скобок:
\n"; } $my_func = "foo"; // Теперь мы можем запустить функцию foo() при помощи переменной $my_func, // которая хранит имя указанной функции в виде строки $my_func(); // Вызываем функцию foo() ?>
Такая концепция PHP имеет название «переменные-функции». Она заключается в том, что если добавить к переменной в конце круглые скобки, то интерпретатор PHP проверит сначала, не существует ли функции с именем равным значению переменной и если такая функция есть - выполнит ее.
Так, как показано в примере выше, можно делать только с функциями определенными пользователями. Встроенные языковые конструкции и функции, такие как echo, unset(), isset() и другие подобные им нельзя таким же образом напрямую присвоить переменным. Но можно сделать свою функцию-обертку (wrapper) для того, чтобы встроенные языковые конструкции могли работать подобно пользовательским функциям.
Анонимные функции
Анонимная функция - функция, у которой нет собственного имени, иногда можно встретить и другое название таких функций - лямбда функция . Анонимные функции можно передавать другим функциям в качестве аргументов или присваивать переменным, как обычные значения:
Обратите внимание на пример, в конце определения функции есть точка с запятой, так как анонимная функция является по своей сути значением, и мы присваиваем значение переменной, то в конце как и для обычных инструкций ставится точка с запятой.
Анонимные функции отличаются от именованных тем, что создаются только в тот момент, когда до них доходит выполнение, поэтому воспользоваться ими можно только после их определения:
Замыкания или анонимные функции в PHP - это обычные функции, но без имени. Давайте рассмотрим пример такой функции:
В этом примере есть анонимная функция, но нет никакого смысла. Возникает вопрос - как использовать такие функции? Следующий пример поможет разобраться в этом:
В этом примере мы присвоили переменной анонимную функцию, потом запустили выполнение этой функции синтаксисом $closure(); , то есть мы к имени переменной добавили круглые скобки, как при вызове функции. Обратите внимание, при этом знак $ в имени переменной мы не удаляли.
Но этот пример не особо удобный для использования, ведь можно и простые функции использованть.
Как на практике используются замыкания
Обычно анонимные функции или замыкания в PHP используются чтобы передать их в качестве параметров другой функции. В PHP есть несколько встроенных функций, которые в качестве аргумента принимают замыкание, но об этом будет написано ниже.
Давайте ещё усложним наш пример.
Тут мы создали обычную функцию doStuff() и передали ей как параметр нашу анонимную функцию из переменной $closure , а потом запустили её в теле функции doStuff() .
В этом примере в функции doStuff() не хватает проверки переменной $closure на тип. Для того чтобы функция doStuff() работала корректно, в параметре обязательно должна содержаться анонимная функция.
Функция is_callable()
Анонимные функции в PHP реализованы с помощью встроенного класса Closure (PHP 5 >= 5.3.0, PHP 7). То есть каждая анонимная функция является объектом этого класса.
Объекты класса Closure также называют псевдотипом Callbacks / Callables . Принадлежность переменной к этому типу данных можно проверить при помощи функции is_callable() .
"; print_r($closure); } } $closure = function(){ echo "Hello, World!"; }; doStuff($closure); ?>
Обратите внимание, функция gettype определяет тип переменной $closure как объект. Поэтому функция is_object также вернёт значение true , но это не адекватная проверка в нашем случае. Замыкание нужно проверять именно функцией is_callable .
Конструкция use
В анонимной функции можно сделать видимой переменную из родительской области видимости используя конструкцию use . Вот пример:
При помощи ключевого слова use анонимной функции можно передать несколько переменных, они перечесляются в круглых скобках через запятую.
Также важно понимать, что конструкция use делает видимой именно переменные из родительской области видимости, а это не то же самое что и переменные из глобальной области видимости. Глобальная область видимости не меняется со сменой исполнения функций различной степени вложенности.
Аргументы в анонимных функциях
В анонимную функцию можно передать аргументы. Давайте для примера передадим один аргумент в нашу функцию.
" . $argument; }; doStuff($closure); ?>
С аргументами всё очень просто, тут анонимные функции ничем не отличаются от обычных.
Функция preg_replace_callback
Я обещал несколько встроенных в PHP функций, которые принимают в качестве аргумента замыкание, вот одна из них: preg_replace_callback
preg_replace_callback - выполняет поиск по регулярному выражению и замену с использованием callback-функции (замыкания).
Preg_replace_callback ($pattern , $callback, $subject)
- $pattern - искомый шаблон, может быть как строкой, так и массивом строк.
- $callback - вызываемая callback-функция, которой будет передан массив совпавших элементов из строки subject. Callback-функция должна вернуть строку с заменой.
- $subject - строка или массив строк для поиска и замены.
Это краткий синтаксис, подробнее про возможности этой функции можно почитать на сайте мануала по PHP.
Ещё функции принимающие аргументом замыкание: array_filter , array_map , array_reduce , usort .
Функция call_user_func
Функция call_user_func - вызывает пользовательскую функцию, указанную в первом параметре. Возвращает результат функции, или FALSE в случае ошибки.
Примеры использования call_user_func:
Пример использования call_user_func в ООП.
Класс Closure
Как я уже писал, анонимные функции в PHP реализованы с помощью класса Closure . Все анонимные функции являются объектами этого встроенного класса..
Также отмечу, что при вызове объекта как функции, вызывается магический метод __invoke (начиная с PHP5.3).
Sum: " . ($variable + $variable_out); }; } $r = doStuff(); $r(35); doStuff()->__invoke(5);
В Wikipedia сказано, что анонимная функция это функция, которая может существовать без идентификатора. Звучит довольно-таки интересно! В этом уроке я покажу вам несколько примеров того, как можно создать и вызвать функцию нестандартными методами.
Начнём сразу с примеров:
Function Test($var) { echo "This is $var"; }
Это очень простая функция. Теперь помимо обычного вызова, мы можем запустить эту функцию при помощи переменной, которая хранит имя данной функции. Примерно вот так:
$f = "Test"; $f("variable function");
Если вы запустите код, то увидите сообщение This is variable function. К сведению сказать, обработка одинарных кавычек срабатывает быстрее, чем двойных.
Такую технику мы можем применять и в ООП. Пример с php.net:
Class Foo { function Variable() { $name = "Bar"; $this->$name(); // This calls the Bar() method } function Bar() { echo "This is Bar"; } } $foo = new Foo(); $funcname = "Variable"; $foo->$funcname(); // This calls $foo->Variable()
Это концепция довольно интересна. Она может быть использована для реализации обратных вызовов, таблиц функций и так далее.
Теперь я попробую объяснить вам, что такое анонимные функции:
$input = array(1, 2, 3, 4, 5); $output = array_filter($input, function ($v) { return $v > 2; });
function ($v) { return $v > 2; } это анонимная функция. Так же мы можем присвоить её переменной, чтобы использовать в дальнейшем.
$max = function ($v) { return $v > 2; }; $input = array(1, 2, 3, 4, 5); $output = array_filter($input, $max);
Теперь познакомимся с новым ключевым словом use. Напишем для этого другую анонимную функцию (работает с PHP 5.3):
$max_comp = function ($max) { return function ($v) use ($max) { return $v > $max; }; }; $input = array(1, 2, 3, 4, 5); $output = array_filter($input, $max_comp(2));
В этом примере мы используем эффект замыкания при помощи ключевого слова use. Эта техника позволяет анонимной функции получать доступ к внешним переменным. Повеяло ветерком процедурного программирования?
Вот ещё один пример попроще:
$string = "Hello World!"; $closure = function() use ($string) { echo $string; }; $closure();
Как я уже сказал, переменные, которые мы хотим использовать (из глобальной области видимости) в таких функциях необходимо передавать через use. Важно отметить, что по умолчание передаётся только значение, так что если вы хотите менять содержание передаваемой переменной и хотите, чтобы оно менялось за пределами анонимной функции, передавайте значение по адресу:
$x = 1;
$closure = function() use (&$x) { ++$x; };
echo $x . "
";
$closure();
echo $x . "
";
$closure();
echo $x . "
";
В этом примере, наш метод изменяет содержание переменной $x при каждом вызове анонимной функции. Если бы мы не передавали адрес переменной, а саму переменную у нас бы вывелось три 1.
Истинная красота «замыкания» в том, что оно не загромождает глобальное пространство имён. Как только анонимная функция выполнила действие, все переменные использующиеся в ней уничтожаются автоматически.