summaryrefslogtreecommitdiff
path: root/documentation/lambda-functions.html
blob: 288c97ba31f347de51be80ac4d47a4ffb3faa08d (plain)
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
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
<h1>Lambda functions</h1>
<p>
    C++ and PHP both support lambda functions or anonymous 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>&lt;?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;
});

?&gt;
</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 Php::Parmeters object as its parameter, which is a std::vector of 
    Php::Value objects.
</p>
<p>
<pre class="language-c++"><code>#include &lt;phpcpp.h&gt;
/**
 *  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 &amp;params)
{
    // make sure the function was really called with at least one parameter
    if (params.size() == 0) return;

    // this function is called from PHP user space, and it is called
    // with a anonymous function as its first parameter
    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 callback 
    function. The following function is a simple version of the 
    PHP array_map() function:
</p>
<p>
<pre class="language-php"><code>&lt;?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_array_map($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;
}
?&gt;
</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 &lt;phpcpp.h&gt;
/**
 *  Native function that is callable from PHP
 */
void run_test()
{
    // create the anonymous function
    Php::Function multiply_by_two([](Php::Parameters &amp;params) -> Php::Value {
        
        // make sure the function was really called with at least 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 param * 2;
    });

    // the function now is callable
    Php::Value four = multiply_by_two(2);
    
    // a Php::Function object is a derived Php::Value, and its value can 
    // also be stored in a normal Php::Value object, it will then still 
    // be a callback function then
    Php::Value value = multiply_by_two;
    
    // the value object now also holds the 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_array_map", 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. 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, and skip the Php::Function 
    constructor, but that is 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>
<h2>Signature of the C++ function</h2>
<p>
    You can pass different sort of C++ functions to the Php::Function
    constructor, as long as they are compatible with the following two
    function signatures:
</p>
<p>
<pre class="language-c++"><code>
Php::Value function();
Php::Value function(Php::Parameters &amp;params);
</code></pre>
</p>
<p>
    Internally, the Php::Function class uses a C++ std::function object 
    to store the function, so anything that can be stored in such a 
    std::function object, can be assigned to the Php::Function class.
</p>