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
|
<h1>Magic methods and interfaces</h1>
<p>
PHP classes have a number of magic methods that you can implement to
enable special features. These are methods like __toString(), __get(), __set(),
__invoke(), etcetera. The PHP-CPP library also allows you to implement these
magic methods.
</p>
<p>
Besides that, a core PHP installation also comes with a number of interfaces
that you can implement to add even more special features to a class. These
are interfaces with names like 'Countable', 'ArrayAccess' and 'Serializable'.
The features that these interfaces bring, can also be implemented using
PHP-CPP.
</p>
<p>
There does not seem to be any uniformity in the Zend engine in the choice
between magic methods and interfaces. To us it is unclear why some special features
are implemented with magic methods, while others are activated by implementing
interfaces. In our eyes the Serializable interface could just as well have
been implemented with magic __serialize() and __unserialize() methods, or the
__invoke() method could just as well have been an "Invokable" interface.
PHP is not a standardized language, and some things just seem to the way they
are because someone felt like implementing it this way or another...
</p>
<p>
The PHP-CPP library tries to stay as close to PHP as possible. That's why in
your C++ classes you can also override the magic methods and implement the
special interfaces - and because C++ does not have interfaces like PHP has,
we use classes with pure virtual methods instead.
</p>
<h2>Support for the SPL</h2>
<p>
A standard PHP installation comes with the Standard PHP Library (SPL). This
is an extension that is built on top of the Zend engine and that uses features
from the Zend engine to create classes and interfaces like Countable, Iterator
and ArrayAccess.
</p>
<p>
The PHP-CPP library also has interfaces with these names, and they behave in
more or less the same way as the SPL interfaces. But internally, the PHP-CPP
does not depend on the SPL. If you implement a C++ interface like
Php::ArrayAccess or Php::Countable, it is something different than writing
a class in PHP that implements a SPL interface.
</p>
<p>
Both PHP-CPP and the SPL are directly built on top of the Zend core and
offer the same sort of features, but they do not rely on each other. You can
thus safely use PHP-CPP if you have not loaded the SPL extension.
</p>
<h2>The Countable interface</h2>
<p>
By implementing the Php::Countable interface, you can create objects that
can be passed to the PHP count() function. You have to implement a count()
method that returns the value that you want the count() function to return.
</p>
<p>
<pre class="language-c++"><code>
#include <phpcpp.h>
/**
* The famous counter class, now also implements
* the Php::Countable interface
*/
class Counter : public Php::Base, Php::Countable
{
private:
/**
* The internal counter value
* @var int
*/
int _value = 0;
public:
/**
* C++ constructor and C++ destructpr
*/
Counter() {}
virtual ~Counter() {}
/**
* Methods to increment and decrement the counter
*/
Php::Value increment() { return ++_value; }
Php::Value decrement() { return --_value; }
/**
* Method from the Php::Countable interface, that
* is used when a Counter instance is passed to the
* PHP count() function
*
* @return long
*/
virtual long count() override { return _value; }
};
/**
* Switch to C context to ensure that the get_module() function
* is callable by C programs (which the Zend engine is)
*/
extern "C" {
/**
* Startup function that is called by the Zend engine
* to retrieve all information about the extension
* @return void*
*/
PHPCPP_EXPORT void *get_module() {
// extension object
static Php::Extension myExtension("my_extension", "1.0");
// description of the class so that PHP knows
// which methods are accessible
Php::Class<Counter> counter("Counter");
// add methods
counter.method("increment", &Counter::increment);
counter.method("decrement", &Counter::decrement);
// add the class to the extension
myExtension.add(std::move(counter));
// return the extension
return myExtension;
}
}
</code></pre>
</p>
<p>
The Counter class that we used before has been modified to
show how to make classes that implement the Php::Countable interface.
It is very simple, all you have to to is add the Php::Countable class
as base class. This Php::Countable class has one pure virtual method,
count(), that has to be implemented.
</p>
<p>
And that's is all that you have to do. There is no need to register the
special count() function inside the get_module() function, adding
Php::Countable as base class is sufficient.
</p>
<p>
<pre class="language-php"><code>
<?php
// create a counter
$counter = new Counter();
$counter->increment();
$counter->increment();
$counter->increment();
// show the current value
echo(count($counter)."\n");
?>
</pre></code>
</p>
<p>
The output is, as expected, te value 3.
</p>
|