summaryrefslogtreecommitdiff
path: root/documentation/special-features.html
diff options
context:
space:
mode:
authorEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2014-03-13 16:18:56 +0100
committerEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2014-03-13 16:18:56 +0100
commit40287b042fc252dbf348ae386cf3c9e3cab95d63 (patch)
tree88d737321ad81d0c643e91c81d5805a273024152 /documentation/special-features.html
parent1a8c587f3a67db2e5c38cc525b29800e86f27936 (diff)
update documentation, fixed __compare() method
Diffstat (limited to 'documentation/special-features.html')
-rw-r--r--documentation/special-features.html283
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 &lt;phpcpp.h&gt;
+
+/**
+ * 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&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 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>
+&lt;?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");
+
+?&gt;
+</code></pre>
+</p>
+<h2 id="object-comparison">Comparing objects</h2>
+<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 __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 &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 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 &amp;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&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. 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>
+&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>