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
|
<h1>The lifetime of an extension</h1>
<p>
As we <a href="loading-extension">explained before</a>, the get_module()
function is called when your extension is started. It returns a memory address
where the Zend engine can find all relevant information about your extension.
</p>
<p>
After this get_module() call, your extension is loaded and will be used to handle
<i>multiple</i> pageviews. This is an important difference between standard
PHP scripts and native extensions, because standard PHP scripts handle only a single
pageview. But extensions serve multiple pageviews after each other.
</p>
<p>
This difference is especially important if you use global C++ variables.
Such global variables are initialized when the extension is loaded - and not at
the beginning of each pageview. Changes that you make to global variables keep
their value, and subsequent requests will therefore see the updated values.
</p>
<p>
This, by the way, only happens to <i>native</i> variables. Global PHP variables,
stored in the Php::GLOBALS object, are re-initialized at the beginning of
each request. You do not have to worry about changes that you make to
global PHP variables: at the beginning of the next request, the Php::GLOBALS
object is fresh and new, and the changes that you made during the
previous request are no longer visible.
</p>
<p>
Back to the global C++ variables. If you want to reset a global variable
at the beginning of a new request, you can register a special callback function
that gets called in front of each request.
</p>
<p>
<pre class="language-c++"><code>#include <phpcpp.h>
/**
* Global variable that stores the number of times
* the function updateCounters() has been called in total
* @var int
*/
int invokeTotalCount = 0;
/**
* Global variable that keeps track how many times the
* function updateCounters() was called during the
* current request
* @var int
*/
int invokeDuringRequestCount = 0;
/**
* Native function that is callable from PHP
*
* This function updates a number of global variables that count
* the number of times a function was called
*/
void updateCounters()
{
// increment global counters
invokeTotalCount++;
invokeDuringRequestCount++;
}
/**
* Switch to C context, because the Zend engine expects get 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");
// install a callback that is called at the beginning
// of each request
extension.onRequest([]() {
// re-initialize the counter
invokeDuringRequestCount = 0;
});
// add the updateCounter method to the extension
extension.add("updateCounters", updateCounters);
// return the extension details
return extension;
}
}</code></pre>
</p>
<p>
The Php::Extension class has a method onRequest() that is used in the
above example to register a callback function. This callback is called right
before every pageview/request. And as you can see, it is
permitted to use lambda functions.
</p>
<p>
The onRequest() is not the only method in the Php::Extension object to
register a callback. There are in fact
four different on*() methods that you can use.
</p>
<p>
<ul>
<li>void onStartup(const std::function<void()> &callback);</li>
<li>void onRequest(const std::function<void()> &callback);</li>
<li>void onIdle(const std::function<void()> &callback);</li>
<li>void onShutdown(const std::function<void()> &callback);</li>
</ul>
</p>
<p>
The startup callback is called when the Zend engine has loaded your extension
and all functions and classes in it were registered. If you want to initialize
additional variables in your extension before the functions are going to get called,
you can use the onStartup() function to register a callback to run this
initialization code.
</p>
<p>
After the Zend engine is initialized, it is ready to process requests. In the
example above we used the onRequest() method to register a callback that is
called in front of each request. Next to that, you can also install a callback that gets called
<i>after</i> each request, when the Zend engine moves to an idle state - waiting
for the next request. This can be accomplished with the onIdle()
method in the Php::Extension object.
</p>
<p>
The fourth callback that you can register is a callback that gets called
right before PHP shuts down. If there is anything to clean up, you can install
such a callback and run the cleanup code from it.
</p>
|