diff options
author | Emiel Bruijntjes <emiel.bruijntjes@copernica.com> | 2014-03-13 16:18:56 +0100 |
---|---|---|
committer | Emiel Bruijntjes <emiel.bruijntjes@copernica.com> | 2014-03-13 16:18:56 +0100 |
commit | 40287b042fc252dbf348ae386cf3c9e3cab95d63 (patch) | |
tree | 88d737321ad81d0c643e91c81d5805a273024152 /documentation/special-features.html | |
parent | 1a8c587f3a67db2e5c38cc525b29800e86f27936 (diff) |
update documentation, fixed __compare() method
Diffstat (limited to 'documentation/special-features.html')
-rw-r--r-- | documentation/special-features.html | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/documentation/special-features.html b/documentation/special-features.html new file mode 100644 index 0000000..1569e5f --- /dev/null +++ b/documentation/special-features.html @@ -0,0 +1,283 @@ +<h1>Special features</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 interfaces that are also available in PHP + user space, the Zend engine has additional features that are not exposed via + magic methods, and that only are accessible for extension programmers. These + features available for extensions built with PHP-CPP. +</p> +<h2 id="casting-functions">Extra casting functions</h2> +<p> + Internally, the Zend engine has special casting routines to cast objects + to integers, to booleans and to floating point values. For one reason or another, + a PHP script can only implement the __toString() method, while all other casting + operations are kept away from it. The PHP-CPP library solves this limitation, + and allows one to implement the other casting functions as well. +</p> +<p> + One of the design goals of the PHP-CPP library is to stay as close to PHP as + possible. For that reason the casting functions have been given names that match + the __toString() method: __toInteger(), __toFloat(), and __toBool(). +</p> +<p> +<pre class="language-c++"><code> +#include <phpcpp.h> + +/** + * A sample class, with methods to cast objects to scalars + */ +class MyClass : public Php::Base +{ +public: + /** + * C++ constructor and C++ destructpr + */ + MyClass() {} + virtual ~MyClass() {} + + /** + * Cast to a string + * + * Note that now we use const char* as return value, and not Php::Value. + * The __toString function is detected at compile time, and it does + * not have a fixed signature. You can return any value that can be picked + * up by a Php::Value object. + * + * @return const char * + */ + const char *__toString() + { + return "abcd"; + } + + /** + * Cast to a integer + * @return long + */ + long __toInteger() + { + return 1234; + } + + /** + * Cast to a floating point number + * @return double + */ + double __toFloat() + { + return 88.88; + } + + /** + * Cast to a boolean + * @return bool + */ + bool __toBool() + { + return true; + } +}; + +/** + * 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 casting methods are automatically called when an object is casted + to a scalar type, or when it is used in a scalar context. The following + example demonstrates this. +</p> +<p> +<pre class="language-php"><code> +<?php +// initialize an object +$object = new MyClass(); + +// cast it +echo((string)$object."\n"); +echo((int)$object."\n"); +echo((bool)$object."\n"); +echo((float)$object."\n"); + +?> +</code></pre> +</p> +<h2 id="object-comparison">Comparing objects</h2> +<p> + If you compare two objects in PHP with comparison operators like < ==, != + > (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 __compare method of your class. In other words, if you want to install + a custom comparison operator, you can do so by implementing __compare(). +</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 std::string + */ + std::string Php::Value __toString() + { + return std::to_string(_value); + } + + /** + * Compare with a different object + * @param that + * @return int + */ + int __compare(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. It should return 0 when the two objects are identical, + a value less than zero when the 'this' object is smaller, and higher than + zero when 'this' is bigger. +</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> |