diff options
author | Emiel Bruijntjes <emiel.bruijntjes@copernica.com> | 2014-03-12 13:53:48 +0100 |
---|---|---|
committer | Emiel Bruijntjes <emiel.bruijntjes@copernica.com> | 2014-03-12 13:53:48 +0100 |
commit | 8e792d31f499758d3447da46dc85b68356bdbe9b (patch) | |
tree | a0545bae9fc9e6c28cf93e449b896e583483bf7f | |
parent | f8775b64f67cc464e024cf79cd98eed30c659d25 (diff) |
removed __compare magic method, and added operator< instead
-rw-r--r-- | documentation/comparing-objects.html | 169 | ||||
-rw-r--r-- | include/base.h | 10 | ||||
-rw-r--r-- | include/class.h | 6 | ||||
-rw-r--r-- | src/base.cpp | 10 |
4 files changed, 180 insertions, 15 deletions
diff --git a/documentation/comparing-objects.html b/documentation/comparing-objects.html new file mode 100644 index 0000000..f5c57a9 --- /dev/null +++ b/documentation/comparing-objects.html @@ -0,0 +1,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> + Although we have considered to implement this comparison function as a + magic method (for example __compare), or as a magic interface (for example + Php::Comparable) we have decided to go for the operator< approach that + better fits the C++ language. The big advantage of this choice is that your + objects can now also be used in many C++ STL algorithms, because they use + operator< too. +</p> + diff --git a/include/base.h b/include/base.h index e99023b..d0e7e71 100644 --- a/include/base.h +++ b/include/base.h @@ -220,18 +220,14 @@ public: virtual bool __toBool(); /** - * Compare the object with a different object of the same type + * Comparison operator * - * This method should return 0 if both objects are equal, a negative value - * if the 'this' object is smaller, and a positive value if the 'this' - * object is bigger. - * - * The passed in object is an instance of base + * Check how a different object compares to this object * * @param that Object to compare with * @return int */ - virtual bool __compare(const Base &that) const; + bool operator<(const Base &that) const; private: diff --git a/include/class.h b/include/class.h index eabcec6..427aa64 100644 --- a/include/class.h +++ b/include/class.h @@ -197,7 +197,11 @@ private: T *t2 = (T *)object2; // compare the two objects - return t1->__compare(*t2); + if (*t1 < *t2) return -1; + if (*t1 > *t2) return 1; + + // they must be identical + return 0; } /** diff --git a/src/base.cpp b/src/base.cpp index a77b30f..516663d 100644 --- a/src/base.cpp +++ b/src/base.cpp @@ -256,18 +256,14 @@ bool Base::__toBool() } /** - * Compare the object with a different object of the same type + * Comparison operator * - * This method should return 0 if both objects are equal, a negative value - * if the 'this' object is smaller, and a positive value if the 'this' - * object is bigger. - * - * The passed in object is an instance of base + * Check how a different object compares to this object * * @param that Object to compare with * @return int */ -bool Base::__compare(const Base &that) const +bool Base::operator<(const Base &that) const { // throw an exception that will be caught in the ClassBase class, // so that the default implementation of the function can be called |