summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile50
-rw-r--r--include/argument.h111
-rw-r--r--include/iterator.h102
-rw-r--r--include/value.h2
-rw-r--r--include/valueiterator.h6
-rw-r--r--src/argument.cpp171
-rw-r--r--src/callable.h50
-rw-r--r--src/classimpl.cpp2
-rw-r--r--src/hashiterator.h8
-rw-r--r--src/includes.h3
-rw-r--r--src/invaliditerator.h8
-rw-r--r--src/iteratorimpl.cpp (renamed from src/iterator.cpp)93
-rw-r--r--src/iteratorimpl.h175
-rw-r--r--src/traverseiterator.h8
-rw-r--r--src/valueiteratorimpl.h71
15 files changed, 438 insertions, 422 deletions
diff --git a/Makefile b/Makefile
index ce4c59e..60e82e8 100644
--- a/Makefile
+++ b/Makefile
@@ -55,7 +55,8 @@ INSTALL_LIB = ${INSTALL_PREFIX}/lib
# you can change that here.
#
-LIBRARY = libphpcpp.so
+PHP_LIBRARY = libphpcpp.so
+HHVM_LIBRARY = libhhvmcpp.so
#
@@ -84,7 +85,9 @@ LINKER = g++
# you want to leave that flag out on production servers).
#
-COMPILER_FLAGS = -Wall -c `php-config --includes` -g -std=c++11 -fpic -o
+COMPILER_FLAGS = -Wall -c -g -std=c++11 -fpic
+PHP_COMPILER_FLAGS = ${COMPILER_FLAGS} `php-config --includes`
+HHVM_COMPILER_FLAGS = ${COMPILER_FLAGS}
#
# Linker flags
@@ -96,7 +99,9 @@ COMPILER_FLAGS = -Wall -c `php-config --includes` -g -std=c++11 -fpic -o
# to the linker flags
#
-LINKER_FLAGS = -shared `php-config --ldflags`
+LINKER_FLAGS = -shared
+PHP_LINKER_FLAGS = ${LINKER_FLAGS} `php-config --ldflags`
+HHVM_LINKER_FLAGS = ${LINKER_FLAGS}
#
@@ -118,19 +123,22 @@ MKDIR = mkdir -p
# src/ directory for all *.cpp files. No changes are probably necessary here
#
-LIBRARY_SOURCES = $(wildcard src/*.cpp)
-
+SOURCES = $(wildcard src/*.cpp)
+PHP_SOURCES = $(wildcard src/zend/*.cpp)
+HHVM_SOURCES = $(wildcard src/hhvm/*.cpp)
#
# The object files
#
# The intermediate object files are generated by the compiler right before
-# the linker turns all these object files into the libphpcpp.so shared library.
-# We also use a Makefile function here that takes all source files.
+# the linker turns all these object files into the libphpcpp.so and
+# libhhvmcpp.so shared libraries. We also use a Makefile function here that
+# takes all source files.
#
-LIBRARY_OBJECTS = $(LIBRARY_SOURCES:%.cpp=%.o)
-
+OBJECTS = $(SOURCES:%.cpp=%.o)
+PHP_OBJECTS = $(PHP_SOURCES:%.cpp=%.o)
+HHVM_OBJECTS = $(HHVM_SOURCES:%.cpp=%.o)
#
# Configuration program
@@ -149,25 +157,35 @@ CONFIG_FLAGS = `php-config --includes` -o
# dependencies that are used by the compiler.
#
-all: ${LIBRARY_OBJECTS} ${LIBRARY} ${CONFIG_UTILITY}
+all: ${PHP_LIBRARY} ${CONFIG_UTILITY}
+
+${PHP_LIBRARY}: ${OBJECTS} ${PHP_OBJECTS}
+ ${LINKER} ${PHP_LINKER_FLAGS} -o $@ ${OBJECTS} ${PHP_OBJECTS}
-${LIBRARY}: ${LIBRARY_OBJECTS}
- ${LINKER} ${LINKER_FLAGS} -o $@ ${LIBRARY_OBJECTS}
+${HHVM_LIBRARY}: ${OBJECTS} ${HHVM_OBJECTS}
+ ${LINKER} ${HHVM_LINKER_FLAGS} -o $@ ${OBJECTS} ${HHVM_OBJECTS}
${CONFIG_UTILITY}:
${COMPILER} ${CONFIG_FLAGS} $@ ${CONFIG_SOURCES}
clean:
- ${RM} ${LIBRARY_OBJECTS} ${LIBRARY} ${CONFIG_UTILITY}
+ ${RM} ${OBJECTS} ${PHP_OBJECTS} ${HHVM_OBJECTS} ${PHP_LIBRARY} ${HHVM_LIBRARY} ${CONFIG_UTILITY}
+
+${OBJECTS}:
+ ${COMPILER} ${PHP_COMPILER_FLAGS} -o $@ ${@:%.o=%.cpp}
+
+${PHP_OBJECTS}:
+ ${COMPILER} ${PHP_COMPILER_FLAGS} -o $@ ${@:%.o=%.cpp}
-${LIBRARY_OBJECTS}:
- ${COMPILER} ${COMPILER_FLAGS} $@ ${@:%.o=%.cpp}
+${HHVM_OBJECTS}:
+ ${COMPILER} ${HHVM_COMPILER_FLAGS} -o $@ ${@:%.o=%.cpp}
install:
${MKDIR} ${INSTALL_HEADERS}/phpcpp
${CP} phpcpp.h ${INSTALL_HEADERS}
${CP} include/*.h ${INSTALL_HEADERS}/phpcpp
- ${CP} ${LIBRARY} ${INSTALL_LIB}
+ ${CP} ${PHP_LIBRARY} ${INSTALL_LIB}
+ ${CP} ${HHVM_LIBRARY} ${INSTALL_LIB}
${CONFIG_UTILITY} > ${INSTALL_HEADERS}/phpcpp/config.h
test:
diff --git a/include/argument.h b/include/argument.h
index 68ac7df..81b1bf4 100644
--- a/include/argument.h
+++ b/include/argument.h
@@ -8,15 +8,10 @@
* classes instead.
*
* @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
- * @copyright 2013 Copernica BV
+ * @copyright 2013, 2014 Copernica BV
*/
/**
- * Forward declaration
- */
-struct _zend_arg_info;
-
-/**
* Set up namespace
*/
namespace Php {
@@ -28,21 +23,9 @@ class Argument
{
public:
/**
- * Copy constructor
- * @param argument
- */
- Argument(const Argument &argument);
-
- /**
- * Move constructor
- * @param argument
- */
- Argument(Argument &&argument);
-
- /**
* Destructor
*/
- virtual ~Argument();
+ virtual ~Argument() {}
protected:
/**
@@ -52,7 +35,8 @@ protected:
* @param required Is this argument required?
* @param byref Is this a reference argument
*/
- Argument(const char *name, Type type, bool required = true, bool byref = false);
+ Argument(const char *name, Type type, bool required = true, bool byref = false) :
+ _name(name), _type(type), _required(required), _byReference(byref) {}
/**
* Constructor
@@ -62,17 +46,11 @@ protected:
* @param required Is this argument required?
* @param byref Is this a reference argument?
*/
- Argument(const char *name, const char *classname, bool nullable = true, bool required = true, bool byref = false);
+ Argument(const char *name, const char *classname, bool nullable = true, bool required = true, bool byref = false) :
+ _name(name), _type(Type::Object), _classname(classname), _nullable(nullable), _required(required), _byReference(byref) {}
public:
/**
- * Fill an arg_info structure with data
- * @param info
- * @internal
- */
- void fill(struct _zend_arg_info *info) const;
-
- /**
* Is this a required argument?
* @return bool
* @internal
@@ -81,19 +59,88 @@ public:
{
return _required;
}
-
+
+ /**
+ * Name of the argument
+ * @return std::string
+ */
+ const std::string &name() const
+ {
+ return _name;
+ }
+
+ /**
+ * Type-hint for the argument
+ * @return Type
+ */
+ Type type() const
+ {
+ return _type;
+ }
+
+ /**
+ * If the type is a class, the name of the class
+ * @return std::string
+ */
+ const std::string &classname() const
+ {
+ return _classname;
+ }
+
+ /**
+ * Is it allowed to pass parameter with a null value?
+ * @return bool
+ */
+ bool allowNull() const
+ {
+ return _nullable;
+ }
+
+ /**
+ * Is this a parameter-by-reference?
+ * @return bool
+ */
+ bool byReference() const
+ {
+ return _byReference;
+ }
+
private:
/**
- * The argument info
- * @var zend_arg_info
+ * Name of the argument
+ * @var std::string
*/
- struct _zend_arg_info *_info;
+ std::string _name;
/**
+ * Type of argument
+ * @var Type
+ */
+ Type _type;
+
+ /**
+ * Classname, if this is a parameter that is supposed to be an instance of a class
+ * @var std::string
+ */
+ std::string _classname;
+
+ /**
+ * May the parameter be null?
+ * @var bool
+ */
+ bool _nullable;
+
+ /**
* Is this a required argument
* @var bool
*/
bool _required;
+
+ /**
+ * Is this a 'by-reference' parameter?
+ * @var bool
+ */
+ bool _byReference;
};
/**
diff --git a/include/iterator.h b/include/iterator.h
index 13b30fc..331c8b3 100644
--- a/include/iterator.h
+++ b/include/iterator.h
@@ -2,19 +2,19 @@
* Iterator.h
*
* Base class for iterators. Extension writers that want to create traversable
- * classes, should override this class and implement all pure virtual methods
- * in it.
+ * classes, should override the Php::Traversable base class. This base class
+ * forces you to implement a getIterator() method that returns an instance of
+ * a Php::Iterator class.
+ *
+ * In this file you find the signature of the Php::Iterator class. It mostly has
+ * pure virtual methods, which means that you should create a derived class
+ * that implements all these methods.
*
* @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
* @copyright 2014 Copernica BV
*/
/**
- * Forward declarations
- */
-struct _zend_object_iterator_funcs;
-
-/**
* Set up namespace
*/
namespace Php {
@@ -64,7 +64,7 @@ public:
*/
virtual void rewind() = 0;
-private:
+protected:
/**
* During the lifetime of the iterator, the object over which
* it iterates is keps as a private variable. This ensures that
@@ -73,92 +73,6 @@ private:
*/
Value _object;
- /**
- * The current() method that is called by the Zend engine wants a
- * pointer-to-pointer-to-a-zval. Because of this, we have to keep the
- * current value in memory after the current() method returns because
- * the pointer would otherwise fall out of scope. This is (once again)
- * odd behavior of the Zend engine, but we'll have to live with that
- * @var Value
- */
- Value _current;
-
- /**
- * Internal method that returns the implementation object
- * @return zend_object_iterator
- */
- struct _zend_object_iterator *implementation();
-
- /**
- * Iterator destructor method
- * @param iter
- * @param tsrm_ls
- */
- static void destructor(struct _zend_object_iterator *iter TSRMLS_DC);
-
- /**
- * Iterator valid function
- * Returns FAILURE or SUCCESS
- * @param iter
- * @param tsrm_ls
- * @return int
- */
- static int valid(struct _zend_object_iterator *iter TSRMLS_DC);
-
- /**
- * Fetch the current item
- * @param iter
- * @param data
- * @param tsrm_ls
- */
- static void current(struct _zend_object_iterator *iter, struct _zval_struct ***data TSRMLS_DC);
-
- /**
- * Fetch the key for the current element (optional, may be NULL). The key
- * should be written into the provided zval* using the ZVAL_* macros. If
- * this handler is not provided auto-incrementing integer keys will be
- * used.
- * @param iter
- * @param data
- * @param tsrm_ls
- */
- static void key(struct _zend_object_iterator *iter, struct _zval_struct *data TSRMLS_DC);
-
- /**
- * Function to retrieve the current key, php 5.3 style
- * @param iter
- * @param str_key
- * @param str_key_len
- * @param int_key
- * @param tsrm_ls
- * @return HASH_KEY_IS_STRING or HASH_KEY_IS_LONG
- */
- static int key(struct _zend_object_iterator *iter, char **str_key, unsigned int *str_key_len, unsigned long *int_key TSRMLS_DC);
-
- /**
- * Step forwards to the next element
- * @param iter
- * @param tsrm_ls
- */
- static void next(struct _zend_object_iterator *iter TSRMLS_DC);
-
- /**
- * Rewind the iterator back to the start
- * @param iter
- * @param tsrm_ls
- */
- static void rewind(struct _zend_object_iterator *iter TSRMLS_DC);
-
- /**
- * Get access to all iterator functions
- * @return zend_object_iterator_funcs
- */
- static struct _zend_object_iterator_funcs *functions();
-
- /**
- * Classbase is a friend
- */
- friend class ClassImpl;
};
/**
diff --git a/include/value.h b/include/value.h
index e7fa825..844f978 100644
--- a/include/value.h
+++ b/include/value.h
@@ -943,7 +943,7 @@ protected:
friend class Globals;
friend class Member;
friend class ClassImpl;
- friend class Iterator;
+ friend class IteratorImpl;
friend class Extension;
friend class HashIterator;
friend class TraverseIterator;
diff --git a/include/valueiterator.h b/include/valueiterator.h
index fd8118d..8bc9208 100644
--- a/include/valueiterator.h
+++ b/include/valueiterator.h
@@ -25,7 +25,7 @@ namespace Php {
/**
* Forward declarations
*/
-class IteratorImpl;
+class ValueIteratorImpl;
/**
* Class definition
@@ -37,7 +37,7 @@ public:
* Constructor
* @param impl Implementation iterator
*/
- ValueIterator(IteratorImpl *impl) : _impl(impl) {}
+ ValueIterator(ValueIteratorImpl *impl) : _impl(impl) {}
/**
* Copy constructor
@@ -125,7 +125,7 @@ private:
* Pointer to the actual implementation
* @var std::unique_ptr
*/
- IteratorImpl *_impl;
+ ValueIteratorImpl *_impl;
};
diff --git a/src/argument.cpp b/src/argument.cpp
deleted file mode 100644
index a2aa8d5..0000000
--- a/src/argument.cpp
+++ /dev/null
@@ -1,171 +0,0 @@
-/**
- * Argument.cpp
- *
- * Implementation for the Argument class
- *
- * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
- * @copyright 2013 Copernica BV
- */
-#include "includes.h"
-
-/**
- * Set up namespace
- */
-namespace Php {
-
-/**
- * Constructor
- * @param name Name of the argument
- * @param type Argument type
- * @param required Is this argument required?
- * @param byref Is this a reference argument
- */
-Argument::Argument(const char *name, Type type, bool required, bool byref)
-{
- // construct object
- _info = new zend_arg_info;
-
- // fill members
- _info->name = name;
- _info->name_len = strlen(name);
-
-#if PHP_VERSION_ID >= 50400
-
- // since php 5.4 there is a type-hint
- _info->type_hint = (unsigned char)(type == Type::Array || type == Type::Callable ? type : Type::Null);
-
-# if PHP_VERSION_ID >= 50600
-
- // from PHP 5.6 and onwards, an is_variadic property can be set, this
- // specifies whether this argument is the first argument that specifies
- // the type for a variable length list of arguments. For now we only
- // support methods and functions with a fixed number of arguments.
- _info->is_variadic = false;
-
-# endif
-
-#else
-
- // php 5.3 code
- _info->array_type_hint = type == Type::Array;
- _info->return_reference = false;
- _info->required_num_args = 0; // @todo is this correct?
-
-#endif
-
- // this parameter is a regular type
- _info->class_name = NULL;
- _info->class_name_len = 0;
- _info->allow_null = false;
- _info->pass_by_reference = byref;
-
- // store if required
- _required = required;
-}
-
-/**
- * Constructor
- * @param name Name of the argument
- * @param classname Name of the class
- * @param nullable Can it be null?
- * @param required Is this argument required?
- * @param byref Is this a reference argument?
- */
-Argument::Argument(const char *name, const char *classname, bool nullable, bool required, bool byref)
-{
- // construct object
- _info = new zend_arg_info;
-
- // fill members
- _info->name = name;
- _info->name_len = strlen(name);
-
-#if PHP_VERSION_ID >= 50400
-
- // since php 5.4 there is a type hint
- _info->type_hint = (unsigned char)Type::Object;
-
-# if PHP_VERSION_ID >= 50600
-
- // from PHP 5.6 and onwards, an is_variadic property can be set, this
- // specifies whether this argument is the first argument that specifies
- // the type for a variable length list of arguments. For now we only
- // support methods and functions with a fixed number of arguments.
- _info->is_variadic = false;
-
-# endif
-
-#else
-
- // php 5.3 code
- _info->array_type_hint = false;
- _info->return_reference = false;
- _info->required_num_args = 0; // @todo is this correct?
-
-#endif
-
- // the parameter is a class
- _info->class_name = classname;
- _info->class_name_len = strlen(classname);
- _info->allow_null = nullable;
- _info->pass_by_reference = byref;
-
- // store if required
- _required = required;
-}
-
-/**
- * Copy constructor
- * @param argument
- */
-Argument::Argument(const Argument &argument)
-{
- // construct object
- _info = new zend_arg_info;
-
- // fill members
- *_info = *argument._info;
-
- // store if required
- _required = argument._required;
-}
-
-/**
- * Move constructor
- * @param argument
- */
-Argument::Argument(Argument &&argument)
-{
- // copy memory pointer
- _info = argument._info;
-
- // forget in other object
- argument._info = nullptr;
-
- // store if required
- _required = argument._required;
-}
-
-/**
- * Destructor
- */
-Argument::~Argument()
-{
- if (_info) delete _info;
-}
-
-/**
- * Fill an arg_info structure with data
- * @param info
- * @internal
- */
-void Argument::fill(struct _zend_arg_info *info) const
-{
- // copy all data
- *info = *_info;
-}
-
-/**
- * End of namespace
- */
-}
diff --git a/src/callable.h b/src/callable.h
index f123c8b..aef5649 100644
--- a/src/callable.h
+++ b/src/callable.h
@@ -43,11 +43,11 @@ public:
// loop through the arguments
for (auto it = arguments.begin(); it != arguments.end(); it++)
{
- // increment required
+ // increment counter with number of required parameters
if (it->required()) _required++;
// fill the arg info
- it->fill(&_argv[i++]);
+ fill(&_argv[i], *it);
}
}
@@ -140,7 +140,53 @@ protected:
* @var zend_arg_info[]
*/
struct _zend_arg_info *_argv = nullptr;
+
+ /**
+ * Private helper method to fill an argument object
+ * @param info object from the zend engine
+ * @param arg original object
+ */
+ void fill(zend_arg_info *info, const Argument &arg) const
+ {
+ // fill members
+ info->name = arg.name().c_str();
+ info->name_len = arg.name().size();
+
+#if PHP_VERSION_ID >= 50400
+
+ // since php 5.4 there is a type-hint, but we only support arrays, objects and callables
+ switch (arg.type()) {
+ case Type::Array: info->type_hint = IS_ARRAY; break;
+ case Type::Callable: info->type_hint = IS_CALLABLE; break;
+ case Type::Object: info->type_hint = IS_OBJECT; break;
+ default: info->type_hint = IS_NULL; break;
+ }
+
+# if PHP_VERSION_ID >= 50600
+
+ // from PHP 5.6 and onwards, an is_variadic property can be set, this
+ // specifies whether this argument is the first argument that specifies
+ // the type for a variable length list of arguments. For now we only
+ // support methods and functions with a fixed number of arguments.
+ info->is_variadic = false;
+
+# endif
+
+#else
+ // php 5.3 code
+ info->array_type_hint = type == Type::Array;
+ info->return_reference = false;
+ info->required_num_args = 0; // @todo is this correct?
+
+#endif
+
+ // this parameter is a regular type
+ info->class_name = arg.type() == Type::Object ? arg.classname().c_str() : nullptr;
+ info->class_name_len = arg.type() == Type::Object ? arg.classname().size() : 0;
+ info->allow_null = arg.allowNull();
+ info->pass_by_reference = arg.byReference();
+ }
};
/**
diff --git a/src/classimpl.cpp b/src/classimpl.cpp
index 3999cf3..ea7fdd7 100644
--- a/src/classimpl.cpp
+++ b/src/classimpl.cpp
@@ -1246,7 +1246,7 @@ zend_object_iterator *ClassImpl::getIterator(zend_class_entry *entry, zval *obje
try
{
// create an iterator
- auto *iterator = traversable->getIterator();
+ auto *iterator = new IteratorImpl(traversable->getIterator());
// return the implementation
return iterator->implementation();
diff --git a/src/hashiterator.h b/src/hashiterator.h
index d68ad4e..b1f409f 100644
--- a/src/hashiterator.h
+++ b/src/hashiterator.h
@@ -20,7 +20,7 @@ namespace Php {
/**
* Class definition
*/
-class HashIterator : public IteratorImpl
+class HashIterator : public ValueIteratorImpl
{
public:
/**
@@ -70,9 +70,9 @@ public:
/**
* Clone the object
* @param tsrm_ls
- * @return IteratorImpl
+ * @return ValueIteratorImpl
*/
- virtual IteratorImpl *clone()
+ virtual ValueIteratorImpl *clone()
{
// create a new instance
return new HashIterator(*this);
@@ -136,7 +136,7 @@ public:
* @param that
* @return bool
*/
- virtual bool equals(const IteratorImpl *that) const override
+ virtual bool equals(const ValueIteratorImpl *that) const override
{
// this always is a hash iterator
HashIterator *other = (HashIterator *)that;
diff --git a/src/includes.h b/src/includes.h
index 10dd4b8..f725ae1 100644
--- a/src/includes.h
+++ b/src/includes.h
@@ -93,10 +93,11 @@
#include "origexception.h"
#include "notimplemented.h"
#include "property.h"
-#include "iteratorimpl.h"
+#include "valueiteratorimpl.h"
#include "hashiterator.h"
#include "invaliditerator.h"
#include "traverseiterator.h"
+#include "iteratorimpl.h"
#include "streambuf.h"
#include "classimpl.h"
diff --git a/src/invaliditerator.h b/src/invaliditerator.h
index 7531d7d..388eca8 100644
--- a/src/invaliditerator.h
+++ b/src/invaliditerator.h
@@ -16,15 +16,15 @@ namespace Php {
/**
* Class definition
*/
-class InvalidIterator : public IteratorImpl
+class InvalidIterator : public ValueIteratorImpl
{
public:
/**
* Clone the object
* @param tsrm_ls
- * @return IteratorImpl
+ * @return ValueIteratorImpl
*/
- virtual IteratorImpl *clone()
+ virtual ValueIteratorImpl *clone()
{
// create a new instance
return new InvalidIterator(*this);
@@ -54,7 +54,7 @@ public:
* @param that
* @return bool
*/
- virtual bool equals(const IteratorImpl *that) const override
+ virtual bool equals(const ValueIteratorImpl *that) const override
{
// the other iterator is also an invalid-iterator, and all invalid
// iterators are equal
diff --git a/src/iterator.cpp b/src/iteratorimpl.cpp
index 0362fb1..2750ddb 100644
--- a/src/iterator.cpp
+++ b/src/iteratorimpl.cpp
@@ -14,20 +14,24 @@
namespace Php {
/**
+ * Helper method to get access to ourselves
+ * @param iter
+ * @return IteratorImpl
+ */
+static IteratorImpl *self(zend_object_iterator *iter)
+{
+ return (IteratorImpl *)iter->data;
+}
+
+/**
* Iterator destructor method
* @param iter
* @param tsrm_ls
*/
-void Iterator::destructor(zend_object_iterator *iter TSRMLS_DC)
+void IteratorImpl::destructor(zend_object_iterator *iter TSRMLS_DC)
{
- // get the actual iterator
- Iterator *iterator = (Iterator *)iter->data;
-
- // delete the iterator
- delete iterator;
-
- // free memory for the meta object
- efree(iter);
+ // delete the object
+ delete self(iter);
}
/**
@@ -37,13 +41,10 @@ void Iterator::destructor(zend_object_iterator *iter TSRMLS_DC)
* @param tsrm_ls
* @return int
*/
-int Iterator::valid(zend_object_iterator *iter TSRMLS_DC)
+int IteratorImpl::valid(zend_object_iterator *iter TSRMLS_DC)
{
- // get the actual iterator
- Iterator *iterator = (Iterator *)iter->data;
-
// check if valid
- return iterator->valid() ? SUCCESS : FAILURE;
+ return self(iter)->valid() ? SUCCESS : FAILURE;
}
/**
@@ -52,10 +53,10 @@ int Iterator::valid(zend_object_iterator *iter TSRMLS_DC)
* @param data
* @param tsrm_ls
*/
-void Iterator::current(zend_object_iterator *iter, zval ***data TSRMLS_DC)
+void IteratorImpl::current(zend_object_iterator *iter, zval ***data TSRMLS_DC)
{
// get the actual iterator
- Iterator *iterator = (Iterator *)iter->data;
+ IteratorImpl *iterator = self(iter);
// retrieve the value (and store it in a member so that it is not
// destructed when the function returns)
@@ -74,13 +75,10 @@ void Iterator::current(zend_object_iterator *iter, zval ***data TSRMLS_DC)
* @param key
* @param tsrm_ls
*/
-void Iterator::key(zend_object_iterator *iter, zval *key TSRMLS_DC)
+void IteratorImpl::key(zend_object_iterator *iter, zval *key TSRMLS_DC)
{
- // get the actual iterator
- Iterator *iterator = (Iterator *)iter->data;
-
// retrieve the key
- Value retval(iterator->key());
+ Value retval(self(iter)->key());
// detach the underlying zval
zval *val = retval.detach();
@@ -98,13 +96,10 @@ void Iterator::key(zend_object_iterator *iter, zval *key TSRMLS_DC)
* @param tsrm_ls
* @return HASH_KEY_IS_STRING or HASH_KEY_IS_LONG
*/
-int Iterator::key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC)
+int IteratorImpl::key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC)
{
- // get the actual iterator
- Iterator *iterator = (Iterator *)iter->data;
-
// retrieve the key
- Value retval(iterator->key());
+ Value retval(self(iter)->key());
// is this a numeric string?
if (retval.isString())
@@ -131,13 +126,10 @@ int Iterator::key(zend_object_iterator *iter, char **str_key, uint *str_key_len,
* @param iter
* @param tsrm_ls
*/
-void Iterator::next(zend_object_iterator *iter TSRMLS_DC)
+void IteratorImpl::next(zend_object_iterator *iter TSRMLS_DC)
{
- // get the actual iterator
- Iterator *iterator = (Iterator *)iter->data;
-
// call the next method
- iterator->next();
+ self(iter)->next();
}
/**
@@ -145,20 +137,17 @@ void Iterator::next(zend_object_iterator *iter TSRMLS_DC)
* @param iter
* @param tsrm_ls
*/
-void Iterator::rewind(zend_object_iterator *iter TSRMLS_DC)
+void IteratorImpl::rewind(zend_object_iterator *iter TSRMLS_DC)
{
- // get the actual iterator
- Iterator *iterator = (Iterator *)iter->data;
-
// call the rewind method
- iterator->rewind();
+ self(iter)->rewind();
}
/**
* Get access to all iterator functions
* @return zend_object_iterator_funcs
*/
-zend_object_iterator_funcs *Iterator::functions()
+zend_object_iterator_funcs *IteratorImpl::functions()
{
// static variable with all functions
static zend_object_iterator_funcs funcs;
@@ -170,12 +159,12 @@ zend_object_iterator_funcs *Iterator::functions()
if (initialized) return &funcs;
// set the members
- funcs.dtor = &Iterator::destructor;
- funcs.valid = &Iterator::valid;
- funcs.get_current_data = &Iterator::current;
- funcs.get_current_key = &Iterator::key;
- funcs.move_forward = &Iterator::next;
- funcs.rewind = &Iterator::rewind;
+ funcs.dtor = &IteratorImpl::destructor;
+ funcs.valid = &IteratorImpl::valid;
+ funcs.get_current_data = &IteratorImpl::current;
+ funcs.get_current_key = &IteratorImpl::key;
+ funcs.move_forward = &IteratorImpl::next;
+ funcs.rewind = &IteratorImpl::rewind;
// invalidate is not yet supported
funcs.invalidate_current = nullptr;
@@ -188,24 +177,6 @@ zend_object_iterator_funcs *Iterator::functions()
}
/**
- * Internal method that returns the implementation object
- * @return zend_object_iterator
- */
-struct _zend_object_iterator *Iterator::implementation()
-{
- // create an iterator
- zend_object_iterator *iterator = (zend_object_iterator *)emalloc(sizeof(zend_object_iterator));
-
- // initialize all properties
- iterator->data = this;
- iterator->index = 0;
- iterator->funcs = functions();
-
- // done
- return iterator;
-}
-
-/**
* End namespace
*/
}
diff --git a/src/iteratorimpl.h b/src/iteratorimpl.h
index babf9f0..0a815e2 100644
--- a/src/iteratorimpl.h
+++ b/src/iteratorimpl.h
@@ -1,9 +1,14 @@
/**
- * IteratorImpl.h
+ * Iterator.h
*
- * Interface that describes what an implementation of an iterator should
- * look like. This is an internal class that extension developers do not
- * need.
+ * Base class for iterators. Extension writers that want to create traversable
+ * classes, should override the Php::Traversable base class. This base class
+ * forces you to implement a getIterator() method that returns an instance of
+ * a Php::Iterator class.
+ *
+ * In this file you find the signature of the Php::Iterator class. It mostly has
+ * pure virtual methods, which means that you should create a derived class
+ * that implements all these methods.
*
* @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
* @copyright 2014 Copernica BV
@@ -19,53 +24,167 @@ namespace Php {
*/
class IteratorImpl
{
-public:
+private:
/**
- * Constructor
+ * Unique pointer to the iterator that is returned by the extension
+ * @var std::unique_ptr
+ */
+ std::unique_ptr<Iterator> _iterator;
+
+ /**
+ * The current() method that is called by the Zend engine wants a
+ * pointer-to-pointer-to-a-zval. Because of this, we have to keep the
+ * current value in memory after the current() method returns because
+ * the pointer would otherwise fall out of scope. This is (once again)
+ * odd behavior of the Zend engine, but we'll have to live with that
+ * @var Value
+ */
+ Value _current;
+
+ /**
+ * The object iterator as is needed by the Zend engine
+ * @var zend_object_iterator
+ */
+ zend_object_iterator _impl;
+
+ /**
+ * Get access to all iterator functions
+ * @return zend_object_iterator_funcs
+ */
+ static zend_object_iterator_funcs *functions();
+
+ /**
+ * Is the iterator on a valid position
+ * @return bool
*/
- IteratorImpl() {}
+ bool valid()
+ {
+ return _iterator->valid();
+ }
/**
- * Destructor
+ * The value at the current position
+ * @return Value
*/
- virtual ~IteratorImpl() {}
+ Value current()
+ {
+ return _iterator->current();
+ }
+
+ /**
+ * The key at the current position
+ * @return Value
+ */
+ Value key()
+ {
+ return _iterator->key();
+ }
+
+ /**
+ * Move to the next position
+ */
+ void next()
+ {
+ return _iterator->next();
+ }
+
+ /**
+ * Rewind the iterator to the front position
+ */
+ void rewind()
+ {
+ return _iterator->rewind();
+ }
+
+ /**
+ * Iterator destructor method
+ * @param iter
+ * @param tsrm_ls
+ */
+ static void destructor(zend_object_iterator *iter TSRMLS_DC);
/**
- * Clone the object
+ * Iterator valid function
+ * Returns FAILURE or SUCCESS
+ * @param iter
* @param tsrm_ls
- * @return IteratorImpl*
+ * @return int
*/
- virtual IteratorImpl *clone() = 0;
+ static int valid(zend_object_iterator *iter TSRMLS_DC);
/**
- * Increment position (pre-increment)
+ * Fetch the current item
+ * @param iter
+ * @param data
* @param tsrm_ls
- * @return bool
*/
- virtual bool increment() = 0;
-
+ static void current(zend_object_iterator *iter, zval ***data TSRMLS_DC);
+
/**
- * Decrement position (pre-decrement)
- * @return bool
+ * Fetch the key for the current element (optional, may be NULL). The key
+ * should be written into the provided zval* using the ZVAL_* macros. If
+ * this handler is not provided auto-incrementing integer keys will be
+ * used.
+ * @param iter
+ * @param data
+ * @param tsrm_ls
*/
- virtual bool decrement() = 0;
+ static void key(zend_object_iterator *iter, zval *data TSRMLS_DC);
/**
- * Compare with other iterator
- * @param that
- * @return bool
+ * Function to retrieve the current key, php 5.3 style
+ * @param iter
+ * @param str_key
+ * @param str_key_len
+ * @param int_key
+ * @param tsrm_ls
+ * @return HASH_KEY_IS_STRING or HASH_KEY_IS_LONG
+ */
+ static int key(zend_object_iterator *iter, char **str_key, unsigned int *str_key_len, unsigned long *int_key TSRMLS_DC);
+
+ /**
+ * Step forwards to the next element
+ * @param iter
+ * @param tsrm_ls
+ */
+ static void next(zend_object_iterator *iter TSRMLS_DC);
+
+ /**
+ * Rewind the iterator back to the start
+ * @param iter
+ * @param tsrm_ls
+ */
+ static void rewind(zend_object_iterator *iter TSRMLS_DC);
+
+public:
+ /**
+ * Constructor
+ * @param iterator The iterator that is implemented by the extension
*/
- virtual bool equals(const IteratorImpl *that) const = 0;
+ IteratorImpl(Iterator *iterator) : _iterator(iterator)
+ {
+ // initialize impl object
+ _impl.data = this;
+ _impl.index = 0;
+ _impl.funcs = functions();
+ }
+
+ /**
+ * Destructor
+ */
+ virtual ~IteratorImpl() {}
/**
- * Derefecence, this returns a std::pair with the current key and value
- * @return std::pair
+ * Internal method that returns the implementation object
+ * @return zend_object_iterator
*/
- virtual const std::pair<Value,Value> &current() const = 0;
-};
+ zend_object_iterator *implementation()
+ {
+ return &_impl;
+ }
+};
/**
* End namespace
*/
}
-
diff --git a/src/traverseiterator.h b/src/traverseiterator.h
index 84c50f0..16f1ce7 100644
--- a/src/traverseiterator.h
+++ b/src/traverseiterator.h
@@ -17,7 +17,7 @@ namespace Php {
/**
* Class definition
*/
-class TraverseIterator : public IteratorImpl
+class TraverseIterator : public ValueIteratorImpl
{
public:
/**
@@ -73,9 +73,9 @@ public:
/**
* Clone the object
* @param tsrm_ls
- * @return IteratorImpl*
+ * @return ValueIteratorImpl*
*/
- virtual IteratorImpl *clone() override
+ virtual ValueIteratorImpl *clone() override
{
// we need the tsrm_ls variable
TSRMLS_FETCH();
@@ -119,7 +119,7 @@ public:
* @param that
* @return bool
*/
- virtual bool equals(const IteratorImpl *that) const override
+ virtual bool equals(const ValueIteratorImpl *that) const override
{
// of course if the objects are identical
if (this == that) return true;
diff --git a/src/valueiteratorimpl.h b/src/valueiteratorimpl.h
new file mode 100644
index 0000000..82c888d
--- /dev/null
+++ b/src/valueiteratorimpl.h
@@ -0,0 +1,71 @@
+/**
+ * ValueIteratorImpl.h
+ *
+ * Interface that describes what an implementation of a value iterator should
+ * look like. This is an internal class that extension developers do not
+ * need. It is used internally inside the ValueIterator class.
+ *
+ * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
+ * @copyright 2014 Copernica BV
+ */
+
+/**
+ * Set up namespace
+ */
+namespace Php {
+
+/**
+ * Class definition
+ */
+class ValueIteratorImpl
+{
+public:
+ /**
+ * Constructor
+ */
+ ValueIteratorImpl() {}
+
+ /**
+ * Destructor
+ */
+ virtual ~ValueIteratorImpl() {}
+
+ /**
+ * Clone the object
+ * @param tsrm_ls
+ * @return ValueIteratorImpl*
+ */
+ virtual ValueIteratorImpl *clone() = 0;
+
+ /**
+ * Increment position (pre-increment)
+ * @param tsrm_ls
+ * @return bool
+ */
+ virtual bool increment() = 0;
+
+ /**
+ * Decrement position (pre-decrement)
+ * @return bool
+ */
+ virtual bool decrement() = 0;
+
+ /**
+ * Compare with other iterator
+ * @param that
+ * @return bool
+ */
+ virtual bool equals(const ValueIteratorImpl *that) const = 0;
+
+ /**
+ * Derefecence, this returns a std::pair with the current key and value
+ * @return std::pair
+ */
+ virtual const std::pair<Value,Value> &current() const = 0;
+};
+
+/**
+ * End namespace
+ */
+}
+