summaryrefslogtreecommitdiff
path: root/documentation/lambda-functions.html
blob: 19b7775d4f8772a0c9b1a34409873591a3758a62 (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
<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>&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 vector of Php::Value objects as its parameters.
</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)
{
    // 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>&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_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;
}
&lt;?&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 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>