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
|
<h1>Exporting native functions</h1>
<p>
An extension can of course only be useful if you can make functions and/or
classes that can be called from PHP scripts. For functions this is
astonishingly simple. As long as you have a native C++ function that has
one of the following signatures, you can call it almost directly from PHP:
</p>
<p>
<pre class="language-c++"><code>
void example1();
void example2(Php::Parameters &params);
Php::Value example3();
Php::Value example4(Php::Parameters &params);
</code></pre>
</p>
<p>
These function signatures show you two important PHP-CPP classes, the
Php::Value class and the Php::Parameters class. The Php::Value class is a
powerful class that does the same as a regular PHP $variable: it can hold
almost any variable (integers, floating pointer numbers, strings, but also
regular and associative arrays and objects). The Php::Parameters class
can be best compared with an array or a vector holding all the parameters
that were passed to your function. We will come back to both classes in
much more detail later on.
</p>
<p>
To make a function callable from PHP, you must <i>add</i> the function
to your extension object, and assign a name to it. This is the
name by which the function becomes callable from within PHP scripts.
</p>
<p>
<pre class="language-c++"><code>
#include <phpcpp.h>
#include <iostream>
void myFunction()
{
std::cout << "example output" << std::endl;
}
extern "C" {
PHPCPP_EXPORT void *get_module() {
static Php::Extension extension("my_extension", "1.0");
extension.add("myFunction", myFunction);
return extension;
}
}
</code></pre>
</p>
<p>
It is not difficult to imagine what the above code does. If you enable
this extension, you can create PHP scripts in which you can cell myFunction(),
which will print "example output" to stdout.
</p>
<p>
As we've said before, there are four types of functions that can be used. In
this first example we showed the most simple one: a function that does not
take any parameter, and that does also not return anything. What if you
want to return a value from your function?
</p>
<p>
<pre class="language-c++"><code>
#include <phpcpp.h>
#include <stdlib.h>
Php::Value myFunction()
{
if (rand() % 2 == 0)
{
return "string";
}
else
{
return 123;
}
}
extern "C" {
PHPCPP_EXPORT void *get_module() {
static Php::Extension extension("my_extension", "1.0");
extension.add("myFunction", myFunction);
return extension;
}
}
</code></pre>
</p>
<p>
Is that cool or not? In PHP it is perfectly legal to make functions that
sometimes return a number, and sometimes return a string. This can not be
done in C++ - a function should always return the same type of variable.
But because the Php::Value class can be used to represent both numeric
variables as well as strings (and arrays, and objects, but more on that
later) - we can now also create native C++ functions that sometimes return
a string and sometimes a numeric value. You can test the function with a
simple PHP script.
</p>
<p>
<pre class="language-php"><code>
<?php
for ($i=0; $i<10; $i++) echo(myFunction()."\n");
?>
</code></pre>
</p>
<p>
What do we see here? We've added four function declarations ("example1",
"example2", "example3" and "example4") to the source code of our extension.
The reason why we've only declared the functions, and not fully implemented
them is to keep the example code relatively small. We assume that the
four example functions are implemented in a different file. In a real world
example you could just as well remove the "extern" keyword and implement the
four functions in the same source file as the get_module() call.
</p>
<p>
The four functions all have a different signature: Some return a value, while
others do not return anything. And some take parameters, while others do not.
Despite the different signature of the functions, they can all be made
available in PHP by adding them to the extension object, by simply calling
the myExtension.add() method. This method takes two parameters: the name by
which the function should be accessible in PHP, and the actual native
function.
</p>
<p>
In the example above we've used different names for the native functions
("example1" up to "example4") as for the PHP functions ("native1" to
"native4"). This is legal - you do not have to use the same names for your
native functions as for your PHP functions. The following PHP script can be
used to call the four native functions:
</p>
<p>
<code><pre>
<?php
native1();
native2("a","b");
$x = native3();
$y = native4(1,2);
?>
</pre></code>
</p>
<p>
It is not possible to export every thinkable C/C++ function to the
PHP extension. Only functions that have one of the four supported signatures
can be exported: functions that return
void or a Php::Value object, and that either accept a Php::Parameters object
or no parameters at all, can be added to the extension object and can thus
be exported to PHP.
</p>
<h2>Parameter types</h2>
<p>
PHP has a mechanism to enforce function parameters types, and to accept
parameters either by reference or by value. In the examples above, we have
not yet used that mechanism yes: it is up to the function implementations
themselves to inspect the 'Parameters' object, and check if the
variables are of the right type.
</p>
<p>
However, the 'Extension::add()' method takes a third optional parameter that
you can use to specify the number of parameters that are supported, whether
the parameters are passed by reference or by value, and what the type of
the parameters is:
</p>
<p>
<pre class="language-c++"><code>
#include <phpcpp.h>
extern void example(Php::Parameters &params);
extern "C" {
PHPCPP_EXPORT void *get_module() {
static Php::Extension myExtension("my_extension", "1.0");
myExtension.add("example", example, {
Php::ByVal("a", Php::Type::Numeric),
Php::ByVal("b", "ExampleClass"),
Php::ByRef("c", "OtherClass")
});
return myExtension.module();
}
}
</pre></code>
</p>
<p>
Above you see that we passed in additional information when we registered the
"example" function. We tell our extension that our function accepts three parameters:
the first parameter must be a regular number, while the other ones are object
instances of type "ExampleClass" and "OtherClass". In the end, your native C++
"example" function will still be called with a Php::Parameters instance, but
the moment it gets called, you can be sure that the Php::Parameters object
will be filled with three members, and that two of them are objects of the
appropriate type, and that the third one is also passed by reference.
</p>
<h2>Working with variables</h2>
<p>
Variables in PHP are non-typed. A variable can thus hold any possible type:
an integer, string, a floating point number, and even an object or an array.
C++ on the other hand is a typed language. In C++ an integer variable always
has a numeric value, and a string variable always hold a string value.
</p>
<p>
When you mix native code and PHP code, you will need to convert the non-typed
PHP variables into native variables, and the other way round: convert native
variables back into non-typed PHP variables. The PHP-CPP library offers the
"Value" class that makes this a very simple task.
</p>
<p>
|