08 Лямбда-функции.
C ++ и PHP поддерживают лямбда-функции или анонимные функции (в мире C ++ наиболее часто используется слово лямбда, люди PHP говорят об «анонимных функциях»). С PHP-CPP вы можете передавать эти функции с одного языка на другой. Вы можете вызвать анонимную функцию PHP из вашего кода на C ++, а наоборот - вызвать lambda из C ++ из PHP-скрипта.
Вызов анонимных функций PHP из C ++
Начнем с очень простого примера в PHP. В PHP вы можете создавать анонимные функции и назначать их переменной (или передавать их непосредственно функции).
<?php // анонимная функция PHP, хранящаяся в переменной $f $f = function($a, $b) { // вернуть сумму параметров return $a + $b; }; // передать функцию другой функции other_function($f); // или передать анонимную функцию, не присваивая ее переменной other_function(function() { // вернуть произведение параметров return $a * $b; }); ?>
Вышеприведенный код должен быть знаком большинству PHP-программистов. Конечно, «other_function» может быть реализована в пространстве пользователя PHP, но чтобы продемонстрировать, как это сделать с PHP-CPP, мы собираемся построить его с помощью C ++. Подобно всем другим функциям, которые вы видели в предыдущих примерах, такая функция функций C ++ получает в качестве своего параметра объект Php::Parameters, который является std::vector объектов Php::Value.
#include <phpcpp.h> /** * Собственная функция, вызываемая из PHP * * Эта функция получает один параметр, содержащий вызываемую анонимную * функцию PHP. * * @param params Параметры, передаваемые функции */ void other_function(Php::Parameters ¶ms) { // убедиться, что функция действительно вызывалась хотя бы с одним параметром if (params.size() == 0) return nullptr; // эта функция вызывается из пользовательского пространства PHP и вызывается // с анонимной функцией в качестве первого параметра Php::Value func = params[0]; // класс Php:: Value реализовал оператор (), который позволяет нам // использовать объект так же, как если бы это была реальная функция Php::Value result = func(3, 4); // @todo сделать что-нибудь с результатом } /** * Переключиться на контекст C, потому что механизм Zend ожидает, * что get_module) будет иметь сигнатуру функции стиля C */ extern "C" { /** * Функция запуска, которая автоматически вызывается механизмом Zend * при запуске PHP, и которая должна возвращать детали расширения * @return void* */ PHPCPP_EXPORT void *get_module() { // объект расширения static Php::Extension extension("my_extension", "1.0"); // добавить функцию примера, чтобы ее можно было вызвать из PHP-скриптов extension.add<other_function>("other_function"); // вернуть детали расширения return extension; } }
Это так просто. Но и наоборот. Представьте, что у нас есть функция в PHP-пространстве кода пользователя, которая принимает функцию обратного вызова. Следующая функция представляет собой простую версию функции PHP array_map ():
<?php // функция, которая выполняет итерацию по массиву и вызывает функцию // для каждого элемента этого массива, возвращает новый массив // с каждым элементом, замененным результатом обратного вызова function my_array_map($array, $callback) { // переменная начального результата $result = array(); // цикл по массиву foreach ($array as $index => $item) { // вызов обратного вызова по элементу $result[$index] = $callback($item); } // готово return $result; } ?>
Представьте, что мы хотим называть эту функцию PHP из вашего кода на C++, используя функцию лямбда C++ в качестве обратного вызова. Это возможно и легко:
#include <phpcpp.h> /** * Собственная функция, вызываемая из PHP */ void run_test() { // создание анонимной функции Php::Function multiply_by_two([](Php::Parameters ¶ms) -> Php::Value { // убедитесь, что функция действительно вызывалась хотя бы с одним параметром if (params.empty()) return nullptr; // в функцию передается один параметр Php::Value param = params[0]; // умножьте параметр на два return param * 2; }); // функция теперь вызывается Php::Value four = multiply_by_two(2); // объект Php::Function - это производное значение Php::Value, и его значение // также может быть сохранено в обычном объекте Php::Value, // тогда он все равно будет функцией обратного вызова, тогда Php::Value value = multiply_by_two; // объект значения теперь также содержит функцию Php::Value six = value(3); // create an array Php::Value array; array[0] = 1; array[1] = 2; array[2] = 3; array[3] = 4; // вызвать функцию пользовательского пространства Php::Value result = Php::call("my_array_map", array, multiply_by_two); // @todo что-то делать с переменной результата (которая теперь // содержит массив со значениями 2, 4, 6 и 8). } /** * Переключиться на C-контекст, потому что движок Zend ожидает, * что get_module () будет иметь подпись функции стиля C */ extern "C" { /** * Функция запуска, которая автоматически вызывается механизмом Zend * при запуске PHP, и которая должна возвращать детали расширения * @return void* */ PHPCPP_EXPORT void *get_module() { // объект расширения static Php::Extension extension("my_extension", "1.0"); // добавить функцию примера, чтобы ее можно было вызвать из PHP-скриптов extension.add<run_test>("run_test"); // вернуть детали расширения return extension; } }
В примере мы назначили функцию лямбда C++ объекту Php::Function. Класс Php::Function получен из класса Php::Value. Единственная разница между Php::Value и Php::Function заключается в том, что конструктор Php::Function принимает функцию. Несмотря на эту разницу, оба класса полностью идентичны. На самом деле мы предпочли бы, чтобы функции C++ напрямую привязывались к объектам Php::Value и пропускали конструктор Php::Function, но это невозможно из-за вызова неоднозначностей.
Класс Php::Function можно использовать так, как если бы это был обычный объект Php::Value: вы можете назначить его другим объектам Php::Value, и вы можете использовать его в качестве параметра при вызове функций PHP в пространстве пользователя. В приведенном выше примере мы делаем именно это: мы вызываем функцию my_iterate () пользовательского пространства с помощью нашей собственной функции 'multiply_by_two' C ++.
Подпись функции C ++
Вы можете передавать различные типы функций C++ в конструктор Php::Function, если они совместимы со следующими двумя сигнатурами функций:
Php::Value function(); Php::Value function(Php::Parameters ¶ms);
Внутри класса Php::Function используется объект std::function C ++ для хранения функции, поэтому все, что может быть сохранено в таком объекте std :: function, может быть присвоено классу Php::Function.