diff options
-rw-r--r-- | Makefile | 50 | ||||
-rw-r--r-- | include/argument.h | 111 | ||||
-rw-r--r-- | include/iterator.h | 102 | ||||
-rw-r--r-- | include/value.h | 2 | ||||
-rw-r--r-- | include/valueiterator.h | 6 | ||||
-rw-r--r-- | src/argument.cpp | 171 | ||||
-rw-r--r-- | src/callable.h | 50 | ||||
-rw-r--r-- | src/classimpl.cpp | 2 | ||||
-rw-r--r-- | src/hashiterator.h | 8 | ||||
-rw-r--r-- | src/includes.h | 3 | ||||
-rw-r--r-- | src/invaliditerator.h | 8 | ||||
-rw-r--r-- | src/iteratorimpl.cpp (renamed from src/iterator.cpp) | 93 | ||||
-rw-r--r-- | src/iteratorimpl.h | 175 | ||||
-rw-r--r-- | src/traverseiterator.h | 8 | ||||
-rw-r--r-- | src/valueiteratorimpl.h | 71 |
15 files changed, 438 insertions, 422 deletions
@@ -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> ¤t() 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> ¤t() const = 0; +}; + +/** + * End namespace + */ +} + |