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
|
<h1>Comparing objects</h1>
<p>
One of the questions we had to ask ourselves when we developed the PHP-CPP
library was whether we should follow PHP conventions or follow C++
conventions for many of the library features.
</p>
<p>
PHP uses <a href="magic-methods">magic methods</a> and
<a href="magic-interfaces">magic interfaces</a> to add special behavior to
classes. With C++ you can achieve the same, but by using technologies like
operator overloading, implicit constructors and casting operators. The
PHP __invoke() method for example, is more or less identical to operator ()
in C++.
</p>
<p>
We have decided to follow the PHP conventions, and use magic methods
and magic interfaces in C++ as well - although we must admit that having
methods that start with two underscores does not make the code very
pretty. But by using magic methods the switch from PHP to C++ is kept simpler
for starting C++ programmers. And on top of that, not all magic methods and
interfaces could have been implemented with core C++ features, so we did have
to use <i>some</i> magic methods and/or interfaces anyway.
</p>
<p>
Besides the magic methods and functions, the Zend engine has additional
features that are not exposed via magic methods, and that only are accessible
for extension programmers. We have already mentioned that PHP-CPP allows you
to implement the __toInteger(), __toFloat() and __toBool() methods (next to
the __toString() that can be implemented in PHP scripts too). Another thing
that is not available in PHP but that can be used by extensions is the
possibility to install a custom object comparison procedure.
</p>
<p>
If you compare two objects in PHP with comparison operators like < ==, !=
> (and some others), the Zend engine runs an object comparison function.
The PHP-CPP library interupts this method, and passes the comparison method
to the < operator of your class. In other words, if you want to install
a custom comparison operator, you can do so by implementing operator<.
</p>
<p>
<pre class="language-c++"><code>
#include <phpcpp.h>
/**
* A sample class, that shows how objects can be compared
*/
class MyClass : public Php::Base
{
private:
/**
* Internal value of the class
* @var int
*/
int _value;
public:
/**
* C++ constructor
*/
MyClass()
{
// start with random value
_value = rand();
}
/**
* C++ destructor
*/
virtual ~MyClass() {}
/**
* Cast the object to a string
* @return Php::Value
*/
virtual Php::Value __toString() override
{
return std::to_string(_value);
}
/**
* Comparison operator to compare the object
* @param that
* @return bool
*/
bool operator<(const MyClass &that) const
{
return _value < that._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<MyClass> myClass("MyClass");
// add the class to the extension
myExtension.add(std::move(myClass));
// return the extension
return myExtension;
}
}
</code></pre>
</p>
<p>
The comparison function is automatically called when you try to compare
objects in PHP scripts.
</p>
<p>
<pre class="language-php"><code>
<?php
// initialize a couple of objects
$object1 = new MyClass();
$object2 = new MyClass();
$object3 = new MyClass();
// compare the objects
if ($object1 < $object2)
{
echo("$object1 is smaller than $object2\n");
}
else
{
echo("$object1 is bigger than $object2\n");
}
if ($object1 == $object3)
{
echo("$object1 is equal to $object3\n");
}
else
{
echo("$object1 is not equal to $object3\n");
}
?>
</code></pre>
</p>
<p>
The above PHP script could produce the following output:
</p>
<p>
<pre>
// output
1699622247 is bigger than 151717746
1699622247 is not equal to 627198306
</pre>
</p>
<p>
We have thought about implementing the comparison method as a
magic method (for example __compare()), or as a magic interface (for example
Php::Comparable). In the end we have decided to go for the operator<
approach. It better fits the C++ language, and the big advantage is that your
objects can also be used in many C++ STL algorithms, because these algorithms
also rely on operator<.
</p>
|