summaryrefslogtreecommitdiff
path: root/documentation/comparing-objects.html
blob: ad8b07fc70fbbcc0ca7b213b45d51b1c25f24e23 (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
<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++. The question that we asked ourselves was whether we should automatically 
    pass the __invoke PHP method to a C++ operator() call - or use the same 
    __invoke() method name in C++ too?
</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 - so we could just
    as well follow PHP completely in this.
</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 &lt; ==, !=
    &gt; (and the obvious others), the Zend engine runs an object comparison function.
    The PHP-CPP library interupts this method, and passes the comparison method
    to the &lt; operator of your class. In other words, if you want to install
    a custom comparison operator, you can do so by implementing operator&lt;.
</p>
<p>
<pre class="language-c++"><code>
#include &lt;phpcpp.h&gt;
/**
 *  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&lt;(const MyClass &amp;that) const
    {
        return _value &lt; 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&lt;MyClass&gt; 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>
&lt;?php
// initialize a couple of objects
$object1 = new MyClass();
$object2 = new MyClass();
$object3 = new MyClass();

// compare the objects
if ($object1 &lt; $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");
}
?&gt;
</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&lt; 
    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&lt;.
</p>