1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
|
<h1>Lambda functions</h1>
<p>
C++ and PHP both support lambda functions or anonumous functions (in
the C++ world the word 'lambda' is most used, PHP people speak about
'anonymous functions'). With PHP-CPP you can pass these functions
from one language to the other. It is possible to call an anonymous
PHP function from your C++ code, and the other way around, to call a C++
lambda from a PHP script.
</p>
<h2>Calling anonymous PHP functions from C++</h2>
<p>
Let's start with a very simple example in PHP. In PHP you can create
anonymous functions, and assign them to a variable (or pass them
directly to a function).
</p>
<p>
<pre class="language-php"><code><php
// anonymous PHP function stored in the variable $f
$f = function($a, $b) {
// return the sum of the parameters
return $a + $b;
}
// pass the function to another function
other_function($f);
// or pass an anonymous function without assigning it to a variable
other_function(function() {
// return the product of the parameters
return $a * $b;
});
?>
</code></pre>
</p>
<p>
The code above should be familiar to most PHP programmers. The
'other_function' can of course be implemented in PHP user space,
but to demonstrate how to do this with PHP-CPP we are going to
build it with C++. Just like all the other functions that you've
seen in the earlier examples, such a C++ function function receives
a vector of Php::Value objects as its parameters.
</p>
<p>
<pre class="language-c++"><code>#include <phpcpp.h>
/**
* Native function that is callable from PHP
*
* This function gets one parameter that holds a callable anonynous
* PHP function.
*
* @param params The parameters passed to the function
*/
void other_function(Php::Parameters &params)
{
// first parameter is an anonymous function
Php::Value func = params[0];
// the Php::Value class has implemented the operator (), which allows
// us to use the object just as if it is a real function.
Php::Value result = func(3, 4);
// @todo do something with the result
}
/**
* Switch to C context, because the Zend engine expects the get_module()
* to have a C style function signature
*/
extern "C" {
/**
* Startup function that is automatically called by the Zend engine
* when PHP starts, and that should return the extension details
* @return void*
*/
PHPCPP_EXPORT void *get_module()
{
// the extension object
static Php::Extension extension("my_extension", "1.0");
// add the example function so that it can be called from PHP scripts
extension.add("other_function", other_function);
// return the extension details
return extension;
}
}</code></pre>
</p>
<p>
It is that simple. But the other way around is possible too. Imagine
we have a function in PHP user space code that accepts a function
as it's parameter:
</p>
<p>
<pre class="language-php"><code><php
// function that iterates over an array, and calls a function on every
// element in that array, it returns a new array with every item
// replaced by the result of the callback
function my_iterate($array, $callback) {
// initial result variable
$result = array();
// loop through the array
foreach ($array as $index => $item) {
// call the callback on the item
$result[$index] = $callback($item);
}
// done
return $result;
}
<?>
</code></pre>
</p>
<p>
Imagine that we want to call this PHP function from your C++ code,
using a C++ lambda function as a callback. This is possible, and easy:
</p>
<p>
<pre class="language-c++"><code>#include <phpcpp.h>
/**
* Native function that is callable from PHP
*/
void run_test()
{
// create the anonymous function
Php::Function multiply_by_two([](Php::Parameters &params) -> Php::Value) {
// make sure the function was really called with one parameter
if (params.size() == 0) return nullptr;
// one parameter is passed to the function
Php::Value param = params[0];
// multiple the parameter by two
return params * 2;
});
// the function now is callable
Php::Value four = multiply_by_two(2);
// a Php::Function object is a derived Php::Value, and can be used
// as a normal Php::Value object - it just happen to store a callback,
// it can also be stored in a Php::Value object, without losing
// anything
Php::Value value = multiply_by_two;
// the value object now also holds a function
Php::Value six = value(3);
// create an array
Php::Value array;
array[0] = 1;
array[1] = 2;
array[2] = 3;
array[3] = 4;
// call the user-space function
Php::Value result = Php::call("my_iterate", array, multiply_by_two);
// @todo do something with the result variable (which now holds
// an array with values 2, 4, 6 and 8).
}
/**
* Switch to C context, because the Zend engine expects the get_module()
* to have a C style function signature
*/
extern "C" {
/**
* Startup function that is automatically called by the Zend engine
* when PHP starts, and that should return the extension details
* @return void*
*/
PHPCPP_EXPORT void *get_module()
{
// the extension object
static Php::Extension extension("my_extension", "1.0");
// add the example function so that it can be called from PHP scripts
extension.add("run_test", run_test);
// return the extension details
return extension;
}
}</code></pre>
</p>
<p>
In the example we assigned a C++ lambda function to a Php::Function
object. The Php::Function class is derived from the Php::Value class.
The only difference between a Php::Value and a Php::Function is
that the constructor of Php::Function accepts a function as its
parameter. Despite that difference, both classes are completely
identical. In fact, we would have preferred to make it possible to
assign C++ functions directly to Php::Value objects, but that was
impossible because of calling ambiguities.
</p>
<p>
The Php::Function class can be used as if it is a normal Php::Value
object: you can assign it to other Php::Value objects, and you
can use it as a parameter when you call user space PHP functions.
In the above example we do exactly that: we call the user space
my_iterate() function with our own 'multiply_by_two' C++ function.
</p>
|