php function use variable
Замыкания в 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).
Php function use variable
PHP supports the concept of variable functions. This means that if a variable name has parentheses appended to it, PHP will look for a function with the same name as whatever the variable evaluates to, and will attempt to execute it. Among other things, this can be used to implement callbacks, function tables, and so forth.
Example #1 Variable function example
$func = ‘foo’ ;
$func (); // This calls foo()
$func = ‘bar’ ;
$func ( ‘test’ ); // This calls bar()
$func = ‘echoit’ ;
$func ( ‘test’ ); // This calls echoit()
?>
Object methods can also be called with the variable functions syntax.
Example #2 Variable method example
function Bar ()
<
echo «This is Bar» ;
>
>
When calling static methods, the function call is stronger than the static property operator:
Example #3 Variable method example with static properties
Example #4 Complex callables
class Foo
<
static function bar ()
<
echo «bar\n» ;
>
function baz ()
<
echo «baz\n» ;
>
>
See Also
User Contributed Notes 6 notes
While the documentation suggests that the use of a constant is similar to the use of a variable, there is an exception regarding variable functions. You cannot use a constant as the function name to call a variable function.
const DEBUGME =’func’;
function func($s)
DEBUGME(‘abc’); // results in a syntax error
$call = DEBUGME;
$call(‘abc’); // does the job
But you can use a constant as an argument to a function. Here’s a simple workaround when you need to call a variable constant function:
This makes sense to me to hide API’s and/or long (complicated) static calls.
Enjoy!
List of functions that accept variable arguments.
()
array_diff_key ()
array_diff_uassoc ()
array()
array_intersect_ukey ()
array_map ()
array_merge ()
array_merge_recursive ()
array_multisort ()
array_push ()
array_replace ()
array_replace_recursive ()
array_unshift ()
call_user_func ()
call_user_method ()
compact ()
dba_open ()
dba_popen ()
echo()
forward_static_call ()
fprintf ()
fscanf ()
httprequestpool_construct ()
ibase_execute ()
ibase_set_event_handler ()
ibase_wait_event ()
isset()
list()
maxdb_stmt_bind_param ()
maxdb_stmt_bind_result ()
mb_convert_variables ()
newt_checkbox_tree_add_item ()
newt_grid_h_close_stacked ()
newt_grid_h_stacked ()
newt_grid_v_close_stacked ()
newt_grid_v_stacked ()
newt_win_choice ()
newt_win_entries ()
newt_win_menu ()
newt_win_message ()
newt_win_ternary ()
pack ()
printf ()
register_shutdown_function ()
register_tick_function ()
session_register ()
setlocale ()
sprintf ()
sscanf ()
unset()
var_dump ()
w32api_deftype ()
w32api_init_dtype ()
w32api_invoke_function ()
wddx_add_vars ()
wddx_serialize_vars ()
?>
If you are here looking for a function reference, this is NOT how to do it:
It’s the same as
= «func1» ; // with quotes
?>
You can do echo gettype($choice) to confirm.
So calling
()
?>
is a variable-function for both cases, calling it by its name, not by reference.
A small, but helpful note. If you are trying to call a static function from a different namespace, you must use the fully qualified namespace, even if they have the same top level namespace(s). For example if you have the following class to call:
namespace Project \ TestClass ;
class Test <
static function funcToCall () <
return «test» ;
>
>
?>
You must call it as:
namespace Project \ OtherTestClass ;
class OtherTest <
static function callOtherFunc () <
$func = ‘\Project\TestClass::funcToCall’ ;
$func ();
>
>
?>
and not:
class OtherTest <
static function callOtherFunc () <
$func = ‘TestClass::funcToCall’ ;
$func ();
>
>
?>
If you want to call a static function (PHP5) in a variable method:
Make an array of two entries where the 0th entry is the name of the class to be invoked (‘self’ and ‘parent’ work as well) and the 1st entry is the name of the function. Basically, a ‘callback’ variable is either a string (the name of the function) or an array (0 => ‘className’, 1 => ‘functionName’).
Then, to call that function, you can use either call_user_func() or call_user_func_array(). Examples:
static function c () <
print_r ( func_get_args ());
>
Php function use variable
So you will need to explicitly pass them in by reference if your closure cares about their contents over time:
//set up variable in advance
$myInstance = null ;
//$myInstance might be instantiated, might not be
if( SomeBusinessLogic :: worked () == true )
<
$myInstance = new myClass ();
>
Every instance of a lambda has own instance of static variables. This provides for great event handlers, accumulators, etc., etc.
In case you were wondering (cause i was), anonymous functions can return references just like named functions can. Simply use the & the same way you would for a named function. right after the `function` keyword (and right before the nonexistent name).
PERFORMANCE BENCHMARK 2017!
I decided to compare a single, saved closure against constantly creating the same anonymous closure on every loop iteration. And I tried 10 million loop iterations, in PHP 7.0.14 from Dec 2016. Result:
a single saved closure kept in a variable and re-used (10000000 iterations): 1.3874590396881 seconds
new anonymous closure created each time (10000000 iterations): 2.8460240364075 seconds
In other words, over the course of 10 million iterations, creating the closure again during every iteration only added a total of «1.459 seconds» to the runtime. So that means that every creation of a new anonymous closure takes about 146 nanoseconds on my 7 years old dual-core laptop. I guess PHP keeps a cached «template» for the anonymous function and therefore doesn’t need much time to create a new instance of the closure!
So you do NOT have to worry about constantly re-creating your anonymous closures over and over again in tight loops! At least not as of PHP 7! There is absolutely NO need to save an instance in a variable and re-use it. And not being restricted by that is a great thing, because it means you can feel free to use anonymous functions exactly where they matter, as opposed to defining them somewhere else in the code. 🙂
As of PHP 7.0, you can use IIFE(Immediately-invoked function expression) by wrapping your anonymous function with ().
public function __destruct ()
<
echo «destructed\n» ;
>
>
new Test ;
echo «finished\n» ;
public static function createClosure ()
<
return function () <
>;
>
When using anonymous functions as properties in Classes, note that there are three name scopes: one for constants, one for properties and one for methods. That means, you can use the same name for a constant, for a property and for a method at a time.
Since a property can be also an anonymous function as of PHP 5.3.0, an oddity arises when they share the same name, not meaning that there would be any conflict.
Consider the following example:
class MyClass <
const member = 1 ;
public function member () <
return «method ‘member'» ;
>
header ( «Content-Type: text/plain» );
$myObj = new MyClass ();
/*
* Establish mock authorisation, call the service; should get
* ‘Service returns: test 1’.
*/
$_SESSION [ ‘is_authorised’ ] = true ;
$service ( ‘test 1’ );
/*
* Remove mock authorisation, call the service; should get ‘Access Denied’.
*/
$_SESSION [ ‘is_authorised’ ] = false ;
$service ( ‘test 2’ );
PHP: анонимные функции. Где и как использовать?
В этой записи, я расскажу про анонимные функции в PHP, как и где их использовать. Покажу множество разных примеров использования и дам общие рекомендации по использованию.
Обычная функция vs. анонимная функция
Обычная функция выглядит примерно так:
Вызывается следующим образом:
Анонимная функция (Closure), в PHP дает возможность создавать функцию без имени (например, без printName() как в примере выше). Они части используются в роли callback.
Анонимные функции всегда возвращают Closure. Особо не нагружайте себя почему, чуть ниже, в этом посту я распишу почему так.
Давайте рассмотрим следующий пример анонимной функции:
В самом конце вызываем анонимную функцию добавляя к переменной «()», тем самым делая из нее функцию:
Анонимная функция в переменной
В примере выше, где проводилось сравнение, анонимная функция использовалась в виде переменной.
Чтобы не мешать все в кучу, давайте создадим новый пример:
Анонимная функция как callback
Давайте рассмотрим следующий пример callback функции:
В этом примере, обозначили массив с двумя имена в нижнем регистре. На третье строчке, у нас функция, которые принимает значение параметр в виде имени, переводит первую букву имени в верхний регистр и возвращает результат.
array_map() проходится по массиву с вашим обозначенной callback функцией.
Надо бы переписывать пример выше, так как в реальной жизни вы не должны писать мини функцию в таком случае, иначе размер вашего файла будет расти и расти, а это не есть хорошо 🙂
Смотрите новый вариант, который состоит всего из 5 строк:
Результат точно такой же как и в примере выше.
Создание Closure с анонимной функцией
Давайте рассмотрим такой приме:
Объяснение
Логика doSomething() следующая:
Применение замыканий в 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. Надеюсь, что кто-нибудь нашел для себя здесь что-то новое. И конечно, если кто-то знает еще какие-нибудь интересные применения замыканий, то очень жду ваши комментарии. Спасибо!