summaryrefslogtreecommitdiff
path: root/documentation
diff options
context:
space:
mode:
authorEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2014-03-10 10:39:22 +0100
committerEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2014-03-10 10:39:22 +0100
commitd2e10c764d1b8860dd798eda3055fc957ff556ad (patch)
tree10e6d19cdc71f27e08e0134ad30fe34cd05b7046 /documentation
parent49d88d98a0656233f15923d31ea67a1ed229e514 (diff)
fixed iterators for php 5.3 + updated documentation about iterators
Diffstat (limited to 'documentation')
-rw-r--r--documentation/magic-methods-and-interfaces.html274
1 files changed, 273 insertions, 1 deletions
diff --git a/documentation/magic-methods-and-interfaces.html b/documentation/magic-methods-and-interfaces.html
index 6ece6a5..244ebcd 100644
--- a/documentation/magic-methods-and-interfaces.html
+++ b/documentation/magic-methods-and-interfaces.html
@@ -219,7 +219,7 @@ public:
*/
virtual void offsetSet(const Php::Value &key, const Php::Value &value) override
{
- _map[key] = value;
+ _map[key] = value.stringValue();
}
/**
@@ -311,3 +311,275 @@ echo($map["d"]."\n");
The output speaks for itself. The map has three members, "1234" (a string
variable), "xyz" and "0".
</p>
+<h2>The Traversable interface</h2>
+<p>
+ Classes can also be used in foreach loops, just like regular arrays. If you
+ want to enable this feature, your class should extend from the Php::Traverable
+ base class and implement the getIterator() method.
+</p>
+<p>
+<pre class="language-php"><code>
+&lt;?php
+// fill a map
+$map = new Map();
+$map["a"] = 1234;
+$map["b"] = 5678;
+
+// iterate over it
+foreach ($map as $key => $value)
+{
+ // output the key and value
+ echo("$key: $value\n");
+}
+?&gt;
+</code></pre>
+</p>
+<p>
+ The PHP-CPP library implements iterators in a slightly different manner than
+ the SPL does, and that you are used to if you have been working with PHP.
+ In PHP, to make a class traversable (usable in foreach loops), you have to
+ implement either the Iterator interface, or the IteratorAggregate interface.
+ This is a peculiar architecture - if not to say faulty. When you think of it,
+ it is not the container object itself that is the iterator, that container object is
+ only iterat<i>able</i>! It is <i>being iterated over</i>. In our above example,
+ the $map variable is not the actual iterator, but the container that is
+ iterated over. The real iterator is a hidden object that is not exposed to
+ your PHP script and that controls the foreach loop. The SPL however, would call
+ the map an iterator too.
+</p>
+<p>
+ In PHP-CPP we have therefore decided not to follow the SPL API,
+ and create a completely new way of implementing traversable classes.
+ To make a class traversable, it must be extended from the Php::Traversable
+ base class, that forces you to implement the getIterator() method. This
+ method should return a Php::Iterator instance.
+</p>
+<p>
+ The Php::Iterator object has five methods that are needed for
+ running the foreach loop. Note that your Iterator class does not have to
+ be a class that is accessible from PHP, and does not have to be derived from
+ Php::Base. It is an internal class that is used by foreach loops.
+</p>
+<p>
+<pre class="language-c++"><code>
+#include &lt;phpcpp.h&gt;
+
+/**
+ * A sample iterator class that can be used to iterate
+ * over a map of strings
+ */
+class MapIterator : public Php::Iterator
+{
+private:
+ /**
+ * The map that is being iterated over
+ * This is a reference to the actual map
+ * @var std::map&lt;std::string,std::string&gt;
+ */
+ const std::map&lt;std::string,std::string&gt; &_map;
+
+ /**
+ * The actual C++ iterator
+ * @var std::map&lt;std::string,std::string&gtl;::const_iterator;
+ */
+ std::map&lt;std::string,std::string&gt;::const_iterator _iter;
+
+public:
+ /**
+ * Constructor
+ * @param object The object that is being iterated over
+ * @param map The internal C++ map that is being iterated over
+ */
+ MapIterator(Php::Base *object, const std::map&lt;std::string,std::string&gt; &map) :
+ Php::Iterator(object), _map(map), _iter(map.begin()) {}
+
+ /**
+ * Destructor
+ */
+ virtual ~MapIterator() {}
+
+ /**
+ * Is the iterator on a valid position
+ * @return bool
+ */
+ virtual bool valid() override
+ {
+ return _iter != _map.end();
+ }
+
+ /**
+ * The value at the current position
+ * @return Value
+ */
+ virtual Php::Value current() override
+ {
+ return _iter->second;
+ }
+
+ /**
+ * The key at the current position
+ * @return Value
+ */
+ virtual Php::Value key() override
+ {
+ return _iter->first;
+ }
+
+ /**
+ * Move to the next position
+ */
+ virtual void next() override
+ {
+ _iter++;
+ }
+
+ /**
+ * Rewind the iterator to the front position
+ */
+ virtual void rewind() override
+ {
+ _iter = _map.begin();
+ }
+};
+
+
+/**
+ * A sample Map class, that can be used to map string-to-strings
+ */
+class Map :
+ public Php::Base,
+ public Php::Countable,
+ public Php::ArrayAccess,
+ public Php::Traversable
+{
+private:
+ /**
+ * Internally, a C++ map is used
+ * @var std::map&lt;std::string,std::string&gt;
+ */
+ std::map&lt;std::string,std::string&gt; _map;
+
+public:
+ /**
+ * C++ constructor and C++ destructpr
+ */
+ Map() {}
+ virtual ~Map() {}
+
+ /**
+ * Method from the Php::Countable interface that
+ * returns the number of elements in the map
+ * @return long
+ */
+ virtual long count() override
+ {
+ return _map.size();
+ }
+
+ /**
+ * Method from the Php::ArrayAccess interface that is
+ * called to check if a certain key exists in the map
+ * @param key
+ * @return bool
+ */
+ virtual bool offsetExists(const Php::Value &key) override
+ {
+ return _map.find(key) != _map.end();
+ }
+
+ /**
+ * Set a member
+ * @param key
+ * @param value
+ */
+ virtual void offsetSet(const Php::Value &key, const Php::Value &value) override
+ {
+ _map[key] = value.stringValue();
+ }
+
+ /**
+ * Retrieve a member
+ * @param key
+ * @return value
+ */
+ virtual Php::Value offsetGet(const Php::Value &key) override
+ {
+ return _map[key];
+ }
+
+ /**
+ * Remove a member
+ * @param key
+ */
+ virtual void offsetUnset(const Php::Value &key) override
+ {
+ _map.erase(key);
+ }
+
+ /**
+ * Get the iterator
+ * @return Php::Iterator
+ */
+ virtual Php::Iterator *getIterator() override
+ {
+ // construct a new map iterator on the heap
+ // the (PHP-CPP library will delete it when ready)
+ return new MapIterator(this, _map);
+ }
+};
+
+/**
+ * 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;Map&gt; map("Map");
+
+ // add the class to the extension
+ myExtension.add(std::move(map));
+
+ // return the extension
+ return myExtension;
+ }
+}
+</code></pre>
+</p>
+<p>
+ The above example further extends the Map class. It now implements
+ Php::Countable, Php::ArrayAccess and Php::Traversable. This means that
+ Map objects can now also be used inside foreach loop to iterate over the
+ properties.
+</p>
+<p>
+ For this to work, we has to add the Php::Traversable class as base class
+ to the Map class, and implement the getIterator() method. This method
+ returns a new MapIterator class, which is allocated on the heap. Don't
+ worry about memory management: the PHP-CPP library will destruct your
+ operator the moment the foreach loop is finished.
+</p>
+<p>
+ The MapIterator class is derived from the Php::Iterator class, and
+ implements the five methods that are needed for running foreach
+ loops (current(), key(), next(), rewind() and valid()). Note that the
+ base Php::Iterator class expects that the object over which it iterates
+ is passed to the constructor. This is required so that the iterator object
+ can ensure that this iterated object stays in scope for as long as the
+ iterator exists.
+</p>
+<p>
+ Our MapIterator implementation internally is just a small wrapper around
+ a C++ iterator class. It is of course up to you to create more complex
+ implementation when needed.
+</p>