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 | |
parent | 1a8c587f3a67db2e5c38cc525b29800e86f27936 (diff) |
update documentation, fixed __compare() method
-rw-r--r-- | documentation/magic-methods.html | 135 | ||||
-rw-r--r-- | documentation/special-features.html (renamed from documentation/comparing-objects.html) | 163 | ||||
-rw-r--r-- | include/class.h | 8 |
3 files changed, 212 insertions, 94 deletions
diff --git a/documentation/magic-methods.html b/documentation/magic-methods.html index ed7dd3b..8a1fbfa 100644 --- a/documentation/magic-methods.html +++ b/documentation/magic-methods.html @@ -5,10 +5,18 @@ names like __set(), __isset(), __call(), etcetera. </p> <p> - The PHP-CPP library also has support for these magic methods. The methods - are already defined in the Php::Base class (which is the base class for - all classes that are written using the PHP-CPP library), and can be - overridden in your derived class. + The PHP-CPP library also has support for these magic methods. Using some + C++ compiler tricks, the C++ compiler detects whether the methods exist + in your class, and if they do, they will be compiled into your extension + and called when they are accessed from PHP. +</p> +<p> + The signature of the methods is flexible. Most of the methods accept + Php::Value objects and also return Php::Value objects, but if your own + magic methods have a slightly different signature (they return an integer + for example) it will be picked up by the compiler too because the Php::Value + has many implicit constructors to convert other types into Php::Value + objects. </p> <p> The nice thing about magic methods implemented with PHP-CPP is that they @@ -61,7 +69,7 @@ public: * @param name Name of the property * @return Value Property value */ - virtual Php::Value __get(const Php::Value &name) override + Php::Value __get(const Php::Value &name) { // check if the property name is supported if (name == "name") return _name; @@ -76,7 +84,7 @@ public: * @param name Name of the property * @param value New property value */ - virtual void __set(const Php::Value &name, const Php::Value &value) override + void __set(const Php::Value &name, const Php::Value &value) { // check the property name if (name == "name") @@ -115,7 +123,7 @@ public: * @param name Name of the property * @return bool */ - virtual bool __isset(const Php::Value &name) override + bool __isset(const Php::Value &name) { // true for name and email address if (name == "name" || name == "email") return true; @@ -128,7 +136,7 @@ public: * Remove a property * @param name Name of the property to remove */ - virtual void __unset(const Php::Value &name) override + void __unset(const Php::Value &name) { // name and email can not be unset if (name == "name" || name == "email") @@ -192,7 +200,7 @@ unset($user->email); ?> </code></pre> </p> -<h2 id="call-and-invoke">Magic methods __call() and __invoke()</h2> +<h2 id="call-and-invoke">Magic methods __call(), __callStatic() and __invoke()</h2> <p> C++ methods need to be registered explicitly in your extension get_module() startup function to be accessible from PHP user space. However, when you override the __call() @@ -204,9 +212,14 @@ unset($user->email); __call() method in the C++ class. </p> <p> - Next to the magic __call() function, the PHP-CPP library also supports the - __invoke() method. This is a method that gets called when an object instance - is used <i>as if</i> it was a function. This can be compared with overloading + The __callStatic() method is similar to the __call() method, but works for + static methods. A static call to YourClass::someMethod() can be automatically + passed on to the __callStatic() method of your C++ class. +</p> +<p> + Next to the magic __call() and __callStatic functions, the PHP-CPP library also + supports the __invoke() method. This is a method that gets called when an object + instance is used <i>as if</i> it was a function. This can be compared with overloading the operator () in a C++ class. By implementing the __invoke() method, scripts from PHP user space can create an object, and then use it as a function. </p> @@ -242,10 +255,32 @@ public: * @param params Parameters that were passed to the method * @return Value The return value */ - virtual Php::Value __call(const char *name, Php::Parameters &params) override + Php::Value __call(const char *name, Php::Parameters &params) + { + // the return value + std::string retval = std::string("__call ") + name; + + // loop through the parameters + for (auto &param : params) + { + // append parameter string value to return value + retval += " " + param.stringValue(); + } + + // done + return retval; + } + + /** + * Overriden __callStatic() method to accept all static method calls + * @param name Name of the method that is called + * @param params Parameters that were passed to the method + * @return Value The return value + */ + static Php::Value __callStatic(const char *name, Php::Parameters &params) { // the return value - std::string retval = name; + std::string retval = std::string("__callStatic ") + name; // loop through the parameters for (auto &param : params) @@ -263,7 +298,7 @@ public: * @param params Parameters that were passed to the method * @return Value The return value */ - virtual Php::Value __invoke(Php::Parameters &params) override + Php::Value __invoke(Php::Parameters &params) { // the return value std::string retval = "invoke"; @@ -326,6 +361,11 @@ echo($object->something()."\n"); echo($object->myMethod(1,2,3,4)."\n"); echo($object->whatever("a","b")."\n"); +// call some pseudo-methods in a static context +echo(MyClass::something()."\n"); +echo(MyClass::myMethod(5,6,7)."\n"); +echo(MyClass::whatever("x","y")."\n"); + // call the object as if it was a function echo($object("parameter","passed","to","invoke")."\n"); ?> @@ -338,31 +378,20 @@ echo($object("parameter","passed","to","invoke")."\n"); <p> <pre> regular -something -myMethod 1 2 3 4 -whatever a b +__call something +__call myMethod 1 2 3 4 +__call whatever a b +__callStatic something +__callStatic myMethod 5 6 7 +__callStatic whatever x y invoke parameter passed to invoke </pre> </p> -<h2 id="casting">Casting methods (__toString and more)</h2> +<h2 id="casting">Casting to a string</h2> <p> In PHP you can add a __toString() method to a class. This method is automatically called when an object is casted to a string, or when an object is used in a string - context. PHP-CPP supports this __toString() method too. But there are more casting - methods offered by PHP-CPP. -</p> -<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(). + context. PHP-CPP supports this __toString() method too. </p> <p> <pre class="language-c++"><code> @@ -384,37 +413,10 @@ public: * Cast to a string * @return Value */ - virtual Php::Value __toString() override + Php::Value __toString() { return "abcd"; } - - /** - * Cast to a integer - * @return long - */ - virtual long __toInteger() override - { - return 1234; - } - - /** - * Cast to a floating point number - * @return double - */ - virtual double __toFloat() override - { - return 88.88; - } - - /** - * Cast to a boolean - * @return bool - */ - virtual bool __toBool() override - { - return true; - } }; /** @@ -445,3 +447,12 @@ extern "C" { } </code></pre> </p> +<p> + Next to the magic methods described here, and that you probably already know + from writing PHP scripts, the PHP-CPP library also introduces a number of + additional magic methods. These include extra casting methods, and a method + to compare objects. +</p> +<p> + You can read more about these additional features in the <a href="special-features">next section</a>. +</p> diff --git a/documentation/comparing-objects.html b/documentation/special-features.html index ad8b07f..1569e5f 100644 --- a/documentation/comparing-objects.html +++ b/documentation/special-features.html @@ -1,4 +1,4 @@ -<h1>Comparing objects</h1> +<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++ @@ -25,20 +25,138 @@ 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. + 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 < operator of your class. In other words, if you want to install - a custom comparison operator, you can do so by implementing operator<. + 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> @@ -72,21 +190,21 @@ public: /** * Cast the object to a string - * @return Php::Value + * @return std::string */ - virtual Php::Value __toString() override + std::string Php::Value __toString() { return std::to_string(_value); } /** - * Comparison operator to compare the object + * Compare with a different object * @param that - * @return bool + * @return int */ - bool operator<(const MyClass &that) const + int __compare(const MyClass &that) const { - return _value < that._value; + return _value - that._value; } }; @@ -120,7 +238,9 @@ extern "C" { </p> <p> The comparison function is automatically called when you try to compare - objects in PHP scripts. + 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> @@ -161,12 +281,3 @@ else 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> - diff --git a/include/class.h b/include/class.h index 6fd938c..7e748cf 100644 --- a/include/class.h +++ b/include/class.h @@ -436,7 +436,7 @@ private: * @return bool */ virtual bool callIsset(Base *base, const Value &name) const override - { + { // cast to actual object T *obj = (T *)base; @@ -457,11 +457,7 @@ private: T *t2 = (T *)object2; // compare the two objects - if (*t1 < *t2) return -1; - if (*t2 < *t1) return 1; - - // they must be identical - return 0; + return t1->__compare(*t2); } /** |