что такое callback функция php
Применение замыканий в 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. Надеюсь, что кто-нибудь нашел для себя здесь что-то новое. И конечно, если кто-то знает еще какие-нибудь интересные применения замыканий, то очень жду ваши комментарии. Спасибо!
Что такое callback функция php
В этой статье приводятся примеры вызовов callback-функций в php (вызов статического метода класса, вызов метода объекта, вызов внутри класса и т.д.)
Callback (англ. call — вызов, англ. back — обратный) или фу́нкция обра́тного вы́зова в программировании — передача исполняемого кода в качестве одного из параметров другого кода. Обратный вызов позволяет в функции исполнять код, который задаётся в аргументах при её вызове.
Некоторые функции, такие как call_user_func() или usort() принимают в качестве параметра определенные пользователем callback-функции. Callback-функции могут быть не только простыми функциями, но также и методами объектов, включая статические методы классов.
PHP-функция передается просто как строка ее имени. Можно использовать любую встроенную или пользовательскую функцию, кроме языковых конструкций, таких как: array(), echo(), empty(), eval(), exit(), isset(), list(), print() и unset().
Метод созданного объекта передается как массив, содержащий сам объект в элементе с индексом 0 и имя метода в элементе с индексом 1.
Статические методы классов также могут быть переданы без создания экземпляра объекта данного класса путем передачи имени класса вместо имени объекта в элементе с индексом 0.
Кроме общих пользовательских функций, create_function() также может быть использована для создания анонимной callback-функции. Начиная с версии PHP 5.3.0 стала возможным также передача замыканий в callback-параметр.
Вариант 1: простой вызов callback
call_user_func(‘barber’, «mushroom»);
Вариант 2: вызов статического метода класса
class myclass <
function say_hello($v)
<
echo «Hello!\n».$v;
>
>
$obj = new myclass();
call_user_func(array($obj, ‘say_hello’), ‘params’);[/PHP]
Вариант 4: вызов относительного статического метода класса (с версии PHP 5.3.0)
Вариант 5: вызов внутри класса
Достоинства и недостатки
Достоинства:
Возможность динамического изменения функциональности (подключения и отключения плагинов/модулей при работе программы).
Возможность неограниченного количества вариантов вызываемой функции без изменения базового (в данном контексте) кода.
Возможность вставки вызываемой функции не только для альтернативного поведения, но и в качестве ещё одной (промежуточной) подпрограммы — обычно для отслеживания операций или изменения параметров для следующей (вызываемой) функции. Таких независимых «дополнительных звеньев» в цепочке вызовов может быть сколько угодно.
Поддержка функций обратного вызова в большинстве современных языков программирования общего назначения.
Недостатки:
Уменьшение производительности, связанной с дополнительными вызовами «обратной функции» — прямо пропорционально «стоимости вызова функции» в среде выполнения и количеству дополнительных вызовов при работе программы.
Ухудшение читаемости исходного кода — для понимания алгоритма программы необходимо отслеживать всю цепочку вызовов.
callback функция
Некоторые функции, такие как call_user_func() или usort() принимают в качестве параметра определенные пользователем callback-функции. Callback-функции могут быть не только простыми функциями, но также и методами объектов, включая статические методы классов.
PHP-функция передается просто как строка ее имени. Можно использовать любую встроенную или пользовательскую функцию, кроме языковых конструкций, таких как: array(), echo(), empty(), eval(), exit(), isset(), list(), print() и unset().
Метод созданного объекта передается как массив, содержащий сам объект в элементе с индексом 0 и имя метода в элементе с индексом 1.
Статические методы классов также могут быть переданы без создания экземпляра объекта данного класса путем передачи имени класса вместо имени объекта в элементе с индексом 0.
Кроме общих пользовательских функций, create_function() также может быть использована для создания анонимной callback-функции. Начиная с версии PHP 5.3.0 стала возможным также передача замыканий в callback-параметр.
Пример #1 Примеры callback-функций
Пример #2 Пример callback-вызова с использованием замыканий
Результат выполнения данного примера:
Замечание: В PHP 4 было необходимо использовать ссылку при создании callback-функции для того, чтобы она указывала на реальный объект, а не на его копию. За подробностями обращайтесь к разделу Объяснение ссылок.
Замечание: Callback-функции, зарегистрированные такими функциями как call_user_func() и call_user_func_array(), не будут вызваны при наличии не пойманного исключения, брошенного в предыдущей callback-функции.
Замыкания в 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).
Введение в колбэк-функции в JavaScript
У этой статьи есть продолжение — там мы рассказываем про работу с сервером и передачу параметров в коллбэк-функции.
При изучении программирования мы привыкаем мыслить последовательно: строки кода выполняются по порядку. Для многих языков это утверждение верно на 100%, но всё начинает меняться, когда речь заходит про асинхронное программирование.
Это статья о том, как работают и зачем нужны колбэк-функции в JavaScript. Это одна из важнейших тем программирования на JavaScript, и ни одна более-менее серьёзная программа не обойдется без применения колбэк-функций.
Что такое колбэк-функция
Колбэк-функция или функция обратного вызова — функция, предназначенная для отложенного выполнения. Проще говоря, она должна быть выполнена после завершения работы другой функции. Чтобы стало понятнее, разберём пример с заказом пиццы.
Колбэк (callback) переводится как «Перезвоните». Действительно, принцип работы колбэков схож с заказом обратного телефонного звонка. Представьте, что вы звоните оператору для заказа пиццы, но срабатывает автоответчик, где приятный голос просит оставаться на линии, пока не освободится оператор, или предлагает заказать обратный звонок. Когда оператор освободится — он перезвонит и примет заказ.
Это прекрасная аналогия для понимания принципов работы колбэков и асинхронности. Вместо ожидания ответа оператора, мы можем заказать обратный звонок и заниматься другими делами. Как только произойдёт колбэк (нам перезвонили), мы сможем выполнить задуманное — заказать пиццу.
Как писать код для колбэков
Посмотрим на колбэки с практической стороны.
Выше мы сказали, что колбэки неразрывно связаны с асинхронностью и позволяют «запланировать» действие, которое будет совершено после выполнения какого-то другого, возможно длительного действия. Пример с заказом пиццы это прекрасно илюстрирует. Давайте посмотрим, как это может выглядеть в коде, но для начала взглянем на синхронный код:
Что в этом коде больше всего бросается в глаза? Правильно — последовательность. Здесь представлен синхронный код, который будет выполнятся последовательно:
Проблема видна невооруженным глазом — пока готовится пицца, мы вынуждены ждать и ничего не делать. Строка readBook() будет выполнена только после приготовления пиццы. Фактически мы начнём читать книгу после приготовления пиццы, а не во время готовки.
Само собой, в реальном мире вместо выпекания пиццы может быть любой долгий процесс, например, запрос на получение данных с сервера.
Такой запрос не выполняется мгновенно: браузеру понадобится время, чтобы найти IP-адрес сервера, установить соединение, передать запрос, дождаться ответа и т.д. Все эти действия занимают разное количество времени. Временные задержки будут постоянно отличаться и зависеть от скорости соединения с сетью, времени выполнения запроса на сервере и некоторых других факторов.
Синхронные запросы к серверу будут блокировать дальнейшее выполнение веб-приложения, и это уже очень плохо. Представьте, что каждый раз при отправке запроса к серверу интерфейс вашего приложения становится полностью недоступным.
Эту проблему решает асинхронность, и длительные операции лучше выполнять именно асинхронно. В этом варианте мы как бы откладываем длительную операцию «на потом» и вместо ожидания завершения выполняем другой код. В этой схеме прозрачно всё, кроме вопроса: «Как выполнить код после завершения асинхронной операции?». Ответ прост — функции обратного вызова.
В JavaScript функции являются объектами высшего порядка. Это означает, что функции можно передавать в другие функции в виде параметров или возвращать в виде результата выполнения.
В первом случае мы вызываем функцию foo при помощи круглых скобок и выводим результат выполнения в консоль. Во втором примере мы не делаем вызов функции (обратите внимание на отсутствие круглых скобок), и в консоль выводится содержимое функции. Выходит, нам ничего не мешает передать функцию в виде параметра для других функций:
Что в итоге? Мы передали ссылку на функцию в виде параметра и вызвали её внутри другой функции. В этом и заключается идея колбэков: мы передаем в виде параметров функции, которые будут вызваны «когда-нибудь потом».
И снова пицца
Вернёмся к примеру с приготовлением пиццы. Попробуем поэкспериментировать с кодом и перевести его на асинхронные рельсы. Напомню, наша задача — попросить приготовить пиццу, и читать книгу, пока пицца не будет готова.
Это рабочий код, попробуйте выполнить его в консоли и посмотреть на результат вывода. Он будет таким:
Как видите, ничего сверхъестественного в колбэках нет. Это обычная функция, которая будет выполнена не сейчас, а когда-нибудь потом. «Когда-нибудь» — не преувеличение. Мы не можем сказать, в какой момент времени это случится, но можем сказать, после какой именно функции — после выполнения функции приготовлении пиццы.