From b4dd030782ae49646cdefa8435e6c8acbbf17745 Mon Sep 17 00:00:00 2001 From: Marcus Boerger Date: Thu, 15 Sep 2005 03:33:04 +0000 Subject: [PATCH] MFH: - Add SplObjectStorage - Add RecursiveFilterIterator - Rename Observer to SplObserver - Rename Subject to SplSubject - Move SPL constants to class constants - Update docu --- ext/spl/examples/directorygraphiterator.inc | 2 +- ext/spl/examples/directorytreeiterator.inc | 2 +- ext/spl/internal/cachingiterator.inc | 22 +- ext/spl/internal/cachingrecursiveiterator.inc | 10 +- ext/spl/internal/fileobject.inc | 3 + .../internal/recursiveiteratoriterator.inc | 54 ++++- ext/spl/php_spl.c | 7 +- ext/spl/spl.php | 27 ++- ext/spl/spl_array.c | 5 + ext/spl/spl_directory.c | 2 +- ext/spl/spl_functions.h | 3 + ext/spl/spl_iterators.c | 86 ++++++- ext/spl/spl_iterators.h | 1 + ext/spl/spl_observer.c | 227 ++++++++++++++++-- ext/spl/spl_observer.h | 5 +- ext/spl/tests/array_009.phpt | 2 +- ext/spl/tests/fileobject_001.phpt | 4 +- ext/spl/tests/iterator_002.phpt | 2 +- ext/spl/tests/iterator_023.phpt | 2 +- ext/spl/tests/observer_001.phpt | 12 +- ext/spl/tests/sxe_004.phpt | 61 ++++- 21 files changed, 456 insertions(+), 83 deletions(-) diff --git a/ext/spl/examples/directorygraphiterator.inc b/ext/spl/examples/directorygraphiterator.inc index ea31aa2b8a..2c417a50b0 100644 --- a/ext/spl/examples/directorygraphiterator.inc +++ b/ext/spl/examples/directorygraphiterator.inc @@ -18,7 +18,7 @@ class DirectoryGraphIterator extends DirectoryTreeIterator { function __construct($path) { - RecursiveIteratorIterator::__construct(new CachingRecursiveIterator(new ParentIterator(new RecursiveDirectoryIterator($path)), CIT_CALL_TOSTRING|CIT_CATCH_GET_CHILD), 1); + RecursiveIteratorIterator::__construct(new CachingRecursiveIterator(new ParentIterator(new RecursiveDirectoryIterator($path)), CachingIterator::CALL_TOSTRING|CachingIterator::CATCH_GET_CHILD), 1); } } diff --git a/ext/spl/examples/directorytreeiterator.inc b/ext/spl/examples/directorytreeiterator.inc index 845e7fdce3..ccf8b0f282 100644 --- a/ext/spl/examples/directorytreeiterator.inc +++ b/ext/spl/examples/directorytreeiterator.inc @@ -21,7 +21,7 @@ class DirectoryTreeIterator extends RecursiveIteratorIterator */ function __construct($path) { - parent::__construct(new CachingRecursiveIterator(new RecursiveDirectoryIterator($path), CIT_CALL_TOSTRING|CIT_CATCH_GET_CHILD), 1); + parent::__construct(new CachingRecursiveIterator(new RecursiveDirectoryIterator($path), CachingIterator::CALL_TOSTRING|CachingIterator::CATCH_GET_CHILD), 1); } /** @return the current element prefixed with ASCII graphics diff --git a/ext/spl/internal/cachingiterator.inc b/ext/spl/internal/cachingiterator.inc index dfefd9987f..f5ca2c3c9d 100755 --- a/ext/spl/internal/cachingiterator.inc +++ b/ext/spl/internal/cachingiterator.inc @@ -9,13 +9,10 @@ * SPL - Standard PHP Library */ -define('CIT_CALL_TOSTRING', 1); -define('CIT_CATCH_GET_CHILD', 2); - /** * @brief Cached iteration over another Iterator * @author Marcus Boerger - * @version 1.1 + * @version 1.2 * @since PHP 5.0 * * This iterator wrapper does a one ahead iteration. This way it knows whether @@ -23,13 +20,16 @@ define('CIT_CATCH_GET_CHILD', 2); * * @note If you want to convert the elements into strings and the inner * Iterator is an internal Iterator then you need to provide the - * flag CIT_CALL_TOSTRING to do the conversion when the actual element + * flag CALL_TOSTRING to do the conversion when the actual element * is being fetched. Otherwise the conversion would happen with the * already changed iterator. If you do not need this then it you should * omit this flag because it costs unneccessary work and time. */ class CachingIterator implements OuterIterator { + const CALL_TOSTRING = 1; + const CATCH_GET_CHILD = 2; + private $it; private $current; private $key; @@ -40,12 +40,12 @@ class CachingIterator implements OuterIterator * * @param it Iterator to cache * @param flags Bitmask: - * - CIT_CALL_TOSTRING (whether to call __toString() for every element) + * - CALL_TOSTRING (whether to call __toString() for every element) */ - function __construct(Iterator $it, $flags = CIT_CALL_TOSTRING) + function __construct(Iterator $it, $flags = self::CALL_TOSTRING) { $this->it = $it; - $this->flags = $flags & (CIT_CALL_TOSTRING|CIT_CATCH_GET_CHILD); + $this->flags = $flags & (self::CALL_TOSTRING|self::CATCH_GET_CHILD); $this->next(); } @@ -64,7 +64,7 @@ class CachingIterator implements OuterIterator if ($this->valid = $this->it->valid()) { $this->current = $this->it->current(); $this->key = $this->it->key(); - if ($this->flags & CIT_CALL_TOSTRING) { + if ($this->flags & self::CALL_TOSTRING) { if (is_object($this->current)) { $this->strValue = $this->current->__toString(); } else { @@ -119,11 +119,11 @@ class CachingIterator implements OuterIterator /** @return the string represenatation that was generated for the current * element - * @throw exception when CIT_CALL_TOSTRING was not specified in constructor + * @throw exception when CALL_TOSTRING was not specified in constructor */ function __toString() { - if (!$this->flags & CIT_CALL_TOSTRING) { + if (!$this->flags & self::CALL_TOSTRING) { throw new exception('CachingIterator does not fetch string value (see CachingIterator::__construct)'); } return $this->strValue; diff --git a/ext/spl/internal/cachingrecursiveiterator.inc b/ext/spl/internal/cachingrecursiveiterator.inc index 72204d9399..5f60d76d5b 100755 --- a/ext/spl/internal/cachingrecursiveiterator.inc +++ b/ext/spl/internal/cachingrecursiveiterator.inc @@ -26,10 +26,10 @@ class CachingRecursiveIterator extends CachingIterator implements RecursiveItera * * @param it Iterator to cache * @param flags Bitmask: - * - CIT_CALL_TOSTRING (whether to call __toString() for every element) - * - CIT_CATCH_GET_CHILD (whether to catch exceptions when trying to get childs) + * - CALL_TOSTRING (whether to call __toString() for every element) + * - CATCH_GET_CHILD (whether to catch exceptions when trying to get childs) */ - function __construct(RecursiveIterator $it, $flags = CIT_CALL_TOSTRING) + function __construct(RecursiveIterator $it, $flags = self::CALL_TOSTRING) { parent::__construct($it, $flags); } @@ -56,7 +56,7 @@ class CachingRecursiveIterator extends CachingIterator implements RecursiveItera $this->getChildren = new CachingRecursiveIterator($child, $this->flags); } catch(Exception $e) { - if (!$this->flags & CIT_CATCH_GET_CHILD) { + if (!$this->flags & self::CATCH_GET_CHILD) { throw $e; } $this->hasChildren = false; @@ -70,7 +70,7 @@ class CachingRecursiveIterator extends CachingIterator implements RecursiveItera /** @return whether the current element has children * @note The check whether the Iterator for the children can be created was - * already executed. Hence when flag CIT_CATCH_GET_CHILD was given in + * already executed. Hence when flag CATCH_GET_CHILD was given in * constructor this fucntion returns false so that getChildren does * not try to access those children. */ diff --git a/ext/spl/internal/fileobject.inc b/ext/spl/internal/fileobject.inc index a2f840a4d4..dd27468742 100755 --- a/ext/spl/internal/fileobject.inc +++ b/ext/spl/internal/fileobject.inc @@ -17,6 +17,9 @@ */ class FileObject implements RecursiveIterator, SeekableIterator { + /** Flag: wheter to suppress new lines */ + const DROP_NEW_LINE = 0x00000001; + private $fp; private $fname; private $line = NULL; diff --git a/ext/spl/internal/recursiveiteratoriterator.inc b/ext/spl/internal/recursiveiteratoriterator.inc index b800cd49ae..61a9d60a27 100755 --- a/ext/spl/internal/recursiveiteratoriterator.inc +++ b/ext/spl/internal/recursiveiteratoriterator.inc @@ -9,11 +9,6 @@ * SPL - Standard PHP Library */ -define('RIT_LEAVES_ONLY', 0); -define('RIT_SELF_FIRST', 1); -define('RIT_CHILD_FIRST', 2); -define('RIT_CATCH_GET_CHILD', 2); - /** * @brief Iterates through recursive iterators * @author Marcus Boerger @@ -26,25 +21,36 @@ define('RIT_CATCH_GET_CHILD', 2); */ class RecursiveIteratorIterator implements OuterIterator { + /** Mode: Only show leaves */ + const LEAVES_ONLY = 0; + /** Mode: Show parents prior to their children */ + const SELF_FIRST = 1; + /** Mode: Show all children prior to their parent */ + const CHILD_FIRST = 2; + + /** Flag: Catches exceptions during getChildren() calls and simply jumps + * to the next element. */ + const CATCH_GET_CHILD = 2; + private $ait = array(); private $count = 0; - private $mode = RIT_LEAVES_ONLY; + private $mode = self::LEAVES_ONLY; private $flags = 0; /** Construct from RecursiveIterator * * @param it RecursiveIterator to iterate * @param mode Operation mode (one of): - * - RIT_LEAVES_ONLY only show leaves - * - RIT_SELF_FIRST show parents prior to their childs - * - RIT_CHILD_FIRST show all childs prior to their parent + * - LEAVES_ONLY only show leaves + * - SELF_FIRST show parents prior to their childs + * - CHILD_FIRST show all children prior to their parent * @param flags Control flags, zero or any combination of the following * (since PHP 5.1). - * - RIT_CATCH_GET_CHILD which catches exceptions during + * - CATCH_GET_CHILD which catches exceptions during * getChildren() calls and simply jumps to the next * element. */ - function __construct(RecursiveIterator $it, $mode = RIT_LEAVES_ONLY, $flags = 0) + function __construct(RecursiveIterator $it, $mode = self::LEAVES_ONLY, $flags = 0) { $this->ait[0] = $it; $this->mode = $mode; @@ -61,6 +67,7 @@ class RecursiveIteratorIterator implements OuterIterator } $this->ait[0]->rewind(); $this->ait[0]->recursed = false; + callNextElement(true); } /** @return whether iterator is valid @@ -110,7 +117,7 @@ class RecursiveIteratorIterator implements OuterIterator } catch (Exception $e) { - if (!($this->flags & RIT_CATCH_GET_CHILD)) + if (!($this->flags & self::CATCH_GET_CHILD)) { throw $e; } @@ -140,8 +147,10 @@ class RecursiveIteratorIterator implements OuterIterator unset($this->ait[$this->count--]); $it = $this->ait[$this->count]; $this->endChildren(); + callNextElement(false); } } + callNextElement(true); } /** @return Sub Iterator at given level or if unspecified the current sub @@ -200,6 +209,27 @@ class RecursiveIteratorIterator implements OuterIterator function endChildren() { } + + private function callNextElement($after_move) + { + if ($this->valid()) + { + if ($after_move) + { + if (($this->mode == self::SELF_FIRST && $this->callHasChildren()) + $this->mode == self::LEAVES_ONLY) + $this->nextElement(); + } + else + { + $this->nextElement(); + } + } + } + + /** Called when the next element is available + */ + function nextElement(); } ?> \ No newline at end of file diff --git a/ext/spl/php_spl.c b/ext/spl/php_spl.c index b0238a0433..1e467765e8 100755 --- a/ext/spl/php_spl.c +++ b/ext/spl/php_spl.c @@ -63,6 +63,7 @@ static zend_class_entry * spl_find_ce_by_name(char *name, int len, zend_bool aut { zend_class_entry **ce; int found; + if (!autoload) { char *lc_name; @@ -169,7 +170,6 @@ PHP_FUNCTION(class_implements) SPL_ADD_CLASS(LimitIterator, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(LogicException, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(NoRewindIterator, z_list, sub, allow, ce_flags); \ - SPL_ADD_CLASS(Observer, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(OuterIterator, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(OutOfBoundsException, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(OutOfRangeException, z_list, sub, allow, ce_flags); \ @@ -177,12 +177,15 @@ PHP_FUNCTION(class_implements) SPL_ADD_CLASS(ParentIterator, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(RangeException, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(RecursiveDirectoryIterator, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(RecursiveFilterIterator, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(RecursiveIterator, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(RecursiveIteratorIterator, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(RuntimeException, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(SeekableIterator, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(SimpleXMLIterator, z_list, sub, allow, ce_flags); \ - SPL_ADD_CLASS(Subject, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(SplObjectStorage, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(SplObserver, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(SplSubject, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(UnderflowException, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(UnexpectedValueException, z_list, sub, allow, ce_flags); \ diff --git a/ext/spl/spl.php b/ext/spl/spl.php index ba2f5dcc4a..9b35f8386d 100755 --- a/ext/spl/spl.php +++ b/ext/spl/spl.php @@ -59,7 +59,7 @@ * * SPL offers an advanced XML handling class: * - * - class SimpleXMLIterator extends simplexml_element extends recursiveiterator + * - class SimpleXMLIterator extends simplexml_element implements RecursiveIterator * * 4) Array Overloading * @@ -97,8 +97,9 @@ * * SPL suggests a standard way of implementing the observer pattern. * - * - interface Observer - * - interface Subject + * - interface SplObserver + * - interface SplSubject + * - class SplObjectStorage * * Some articles about SPL: * - Introducing PHP 5's Standard Library @@ -106,10 +107,14 @@ * - Advanced OOP with SPL in PHP 5 * - The Standard PHP Library, Part 1 * - The Standard PHP Library, Part 2 + * - SPL on PHP Wiki + * - Die Standard PHP Library (SPL) [german] * * Talks on SPL: - * - SPL for the masses [pps] - * - SPL for the masses [pdf] + * - SPL for the masses [pps], [pdf] + * - Debug session 1 [pps], [pdf] + * - Debug session 2 [pps], [pdf] + * - From engine overloading to SPL [pps], [pdf] * * You can download this documentation as a chm file * here. @@ -504,6 +509,12 @@ interface Serializeable */ class ArrayObject implements IteratorAggregate, ArrayAccess, Countable { + /** Properties of the object have their normal functionality + * when accessed as list (var_dump, foreach, etc.) */ + const STD_PROP_LIST = 0x00000001; + /** Array indices can be accessed as properties in read/write */ + const ARRAY_AS_PROPS = 0x00000002; + /** Construct a new array iterator from anything that has a hash table. * That is any Array or Object. * @@ -588,6 +599,12 @@ class ArrayObject implements IteratorAggregate, ArrayAccess, Countable */ class ArrayIterator implements SeekableIterator, ArrayAccess, Countable { + /** Properties of the object have their normal functionality + * when accessed as list (var_dump, foreach, etc.) */ + const STD_PROP_LIST = 0x00000001; + /** Array indices can be accessed as properties in read/write */ + const ARRAY_AS_PROPS = 0x00000002; + /** Construct a new array iterator from anything that has a hash table. * That is any Array or Object. * diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c index 077e4fedc4..a1d40b62df 100755 --- a/ext/spl/spl_array.c +++ b/ext/spl/spl_array.c @@ -1220,6 +1220,11 @@ PHP_MINIT_FUNCTION(spl_array) REGISTER_SPL_IMPLEMENTS(ArrayObject, Countable); REGISTER_SPL_IMPLEMENTS(ArrayIterator, Countable); + REGISTER_SPL_CLASS_CONST_LONG(ArrayObject, "STD_PROP_LIST", SPL_ARRAY_STD_PROP_LIST); + REGISTER_SPL_CLASS_CONST_LONG(ArrayObject, "ARRAY_AS_PROPS", SPL_ARRAY_ARRAY_AS_PROPS); + + REGISTER_SPL_CLASS_CONST_LONG(ArrayIterator, "STD_PROP_LIST", SPL_ARRAY_STD_PROP_LIST); + REGISTER_SPL_CLASS_CONST_LONG(ArrayIterator, "ARRAY_AS_PROPS", SPL_ARRAY_ARRAY_AS_PROPS); return SUCCESS; } /* }}} */ diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index fd7628440a..d77f25a8d9 100755 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -1602,7 +1602,7 @@ PHP_MINIT_FUNCTION(spl_directory) REGISTER_SPL_IMPLEMENTS(FileObject, RecursiveIterator); REGISTER_SPL_IMPLEMENTS(FileObject, SeekableIterator); - REGISTER_LONG_CONSTANT("FO_DROP_NEW_LINE", (long)SPL_FILE_OBJECT_DROP_NEW_LINE, CONST_CS | CONST_PERSISTENT); + REGISTER_SPL_CLASS_CONST_LONG(FileObject, "DROP_NEW_LINE", SPL_FILE_OBJECT_DROP_NEW_LINE); return SUCCESS; } diff --git a/ext/spl/spl_functions.h b/ext/spl/spl_functions.h index 61dae21e68..798456023f 100755 --- a/ext/spl/spl_functions.h +++ b/ext/spl/spl_functions.h @@ -52,6 +52,9 @@ typedef zend_object_value (*create_object_func_t)(zend_class_entry *class_type T #define REGISTER_SPL_PROPERTY(class_name, prop_name) \ spl_register_property(spl_ce_ ## class_name, prop_name, prop_val, prop_flags TSRMLS_CC); +#define REGISTER_SPL_CLASS_CONST_LONG(class_name, const_name, value) \ + zend_declare_class_constant_long(spl_ce_ ## class_name, const_name, sizeof(const_name)-1, (long)value TSRMLS_CC); + void spl_destroy_class(zend_class_entry ** ppce); void spl_register_std_class(zend_class_entry ** ppce, char * class_name, create_object_func_t ctor, function_entry * function_list TSRMLS_DC); diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c index 4eb16ff727..4d491a04a5 100755 --- a/ext/spl/spl_iterators.c +++ b/ext/spl/spl_iterators.c @@ -41,6 +41,7 @@ PHPAPI zend_class_entry *spl_ce_RecursiveIterator; PHPAPI zend_class_entry *spl_ce_RecursiveIteratorIterator; PHPAPI zend_class_entry *spl_ce_FilterIterator; +PHPAPI zend_class_entry *spl_ce_RecursiveFilterIterator; PHPAPI zend_class_entry *spl_ce_ParentIterator; PHPAPI zend_class_entry *spl_ce_SeekableIterator; PHPAPI zend_class_entry *spl_ce_LimitIterator; @@ -92,6 +93,7 @@ typedef struct _spl_recursive_it_object { zend_function *callGetChildren; zend_function *beginChildren; zend_function *endChildren; + zend_function *nextElement; zend_class_entry *ce; } spl_recursive_it_object; @@ -208,9 +210,15 @@ next_step: } } } + if (object->nextElement) { + zend_call_method_with_0_params(&zthis, object->ce, &object->nextElement, "nextelement", NULL); + } object->iterators[object->level].state = RS_NEXT; return /* self */; case RS_SELF: + if (object->nextElement && (object->mode == RIT_SELF_FIRST || object->mode == RIT_CHILD_FIRST)) { + zend_call_method_with_0_params(&zthis, object->ce, &object->nextElement, "nextelement", NULL); + } if (object->mode == RIT_SELF_FIRST) { object->iterators[object->level].state = RS_CHILD; } else { @@ -380,6 +388,10 @@ SPL_METHOD(RecursiveIteratorIterator, __construct) if (intern->endChildren->common.scope == spl_ce_RecursiveIteratorIterator) { intern->endChildren = NULL; } + zend_hash_find(&intern->ce->function_table, "nextelement", sizeof("nextElement"), (void **) &intern->nextElement); + if (intern->nextElement->common.scope == spl_ce_RecursiveIteratorIterator) { + intern->nextElement = NULL; + } ce_iterator = Z_OBJCE_P(iterator); /* respect inheritance, don't use spl_ce_RecursiveIterator */ intern->iterators[0].iterator = ce_iterator->get_iterator(ce_iterator, iterator TSRMLS_CC); iterator->refcount++; @@ -515,7 +527,9 @@ SPL_METHOD(RecursiveIteratorIterator, callGetChildren) return; } else { zend_call_method_with_0_params(&zobject, ce, NULL, "getchildren", &retval); - RETURN_ZVAL(retval, 0, 1); + if (retval) { + RETURN_ZVAL(retval, 0, 1); + } } } /* }}} */ @@ -533,6 +547,13 @@ SPL_METHOD(RecursiveIteratorIterator, endChildren) /* nothing to do */ } /* }}} */ +/* {{{ proto RecursiveIterator RecursiveIteratorIterator::nextElement() + Called when the next element is available */ +SPL_METHOD(RecursiveIteratorIterator, nextElement) +{ + /* nothing to do */ +} /* }}} */ + static union _zend_function *spl_recursive_it_get_method(zval **object_ptr, char *method, int method_len TSRMLS_DC) { union _zend_function *function_handler; @@ -620,6 +641,7 @@ static zend_function_entry spl_funcs_RecursiveIteratorIterator[] = { SPL_ME(RecursiveIteratorIterator, callGetChildren, NULL, ZEND_ACC_PUBLIC) SPL_ME(RecursiveIteratorIterator, beginChildren, NULL, ZEND_ACC_PUBLIC) SPL_ME(RecursiveIteratorIterator, endChildren, NULL, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveIteratorIterator, nextElement, NULL, ZEND_ACC_PUBLIC) {NULL, NULL, NULL} }; @@ -1041,6 +1063,40 @@ SPL_METHOD(FilterIterator, next) spl_filter_it_next(getThis(), intern TSRMLS_CC); } /* }}} */ +/* {{{ proto RecursiveFilterIterator::__construct(RecursiveIterator it) + Create a RecursiveFilterIterator from a RecursiveIterator */ +SPL_METHOD(RecursiveFilterIterator, __construct) +{ + spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveIterator, DIT_Default); +} /* }}} */ + +/* {{{ proto boolean RecursiveFilterIterator::hasChildren() + Check whether the inner iterator's current element has children */ +SPL_METHOD(RecursiveFilterIterator, hasChildren) +{ + spl_dual_it_object *intern; + zval *retval; + + intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "haschildren", &retval); + RETURN_ZVAL(retval, 0, 1); +} /* }}} */ + +/* {{{ proto RecursiveFilterIterator RecursiveFilterIterator::getChildren() + Return the inner iterator's children contained in a RecursiveFilterIterator */ +SPL_METHOD(RecursiveFilterIterator, getChildren) +{ + spl_dual_it_object *intern; + zval *retval; + + intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &retval); + spl_instantiate_arg_ex1(spl_ce_RecursiveFilterIterator, &return_value, 0, retval TSRMLS_CC); + zval_ptr_dtor(&retval); +} /* }}} */ + /* {{{ proto ParentIterator::__construct(RecursiveIterator it) Create a ParentIterator from a RecursiveIterator */ SPL_METHOD(ParentIterator, __construct) @@ -1142,9 +1198,17 @@ static zend_function_entry spl_funcs_FilterIterator[] = { static ZEND_BEGIN_ARG_INFO(arginfo_parent_it___construct, 0) - ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0) + ZEND_ARG_OBJ_INFO(0, iterator, RecursiveIterator, 0) ZEND_END_ARG_INFO(); +static zend_function_entry spl_funcs_RecursiveFilterIterator[] = { + SPL_ME(RecursiveFilterIterator, __construct, arginfo_parent_it___construct, ZEND_ACC_PUBLIC) + SPL_MA(ParentIterator, accept, RecursiveFilterIterator, hasChildren, NULL, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveFilterIterator, hasChildren, NULL, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveFilterIterator, getChildren, NULL, ZEND_ACC_PUBLIC) + {NULL, NULL, NULL} +}; + static zend_function_entry spl_funcs_ParentIterator[] = { SPL_ME(ParentIterator, __construct, arginfo_parent_it___construct, ZEND_ACC_PUBLIC) SPL_MA(ParentIterator, accept, ParentIterator, hasChildren, NULL, ZEND_ACC_PUBLIC) @@ -1931,17 +1995,19 @@ PHP_MINIT_FUNCTION(spl_iterators) spl_ce_RecursiveIteratorIterator->get_iterator = spl_recursive_it_get_iterator; spl_ce_RecursiveIteratorIterator->iterator_funcs.funcs = &spl_recursive_it_iterator_funcs; - REGISTER_LONG_CONSTANT("RIT_LEAVES_ONLY", (long)RIT_LEAVES_ONLY, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("RIT_SELF_FIRST", (long)RIT_SELF_FIRST, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("RIT_CHILD_FIRST", (long)RIT_CHILD_FIRST, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("RIT_CATCH_GET_CHILD", (long)RIT_CATCH_GET_CHILD, CONST_CS | CONST_PERSISTENT); + REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "LEAVES_ONLY", RIT_LEAVES_ONLY); + REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "SELF_FIRST", RIT_SELF_FIRST); + REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "CHILD_FIRST", RIT_CHILD_FIRST); + REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "CATCH_GET_CHILD", RIT_CATCH_GET_CHILD); REGISTER_SPL_STD_CLASS_EX(FilterIterator, spl_dual_it_new, spl_funcs_FilterIterator); REGISTER_SPL_ITERATOR(FilterIterator); spl_ce_FilterIterator->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; - REGISTER_SPL_SUB_CLASS_EX(ParentIterator, FilterIterator, spl_dual_it_new, spl_funcs_ParentIterator); - REGISTER_SPL_IMPLEMENTS(ParentIterator, RecursiveIterator); + REGISTER_SPL_SUB_CLASS_EX(RecursiveFilterIterator, FilterIterator, spl_dual_it_new, spl_funcs_RecursiveFilterIterator); + REGISTER_SPL_IMPLEMENTS(RecursiveFilterIterator, RecursiveIterator); + + REGISTER_SPL_SUB_CLASS_EX(ParentIterator, RecursiveFilterIterator, spl_dual_it_new, spl_funcs_ParentIterator); REGISTER_SPL_INTERFACE(SeekableIterator); REGISTER_SPL_ITERATOR(SeekableIterator); @@ -1952,8 +2018,8 @@ PHP_MINIT_FUNCTION(spl_iterators) REGISTER_SPL_STD_CLASS_EX(CachingIterator, spl_dual_it_new, spl_funcs_CachingIterator); REGISTER_SPL_ITERATOR(CachingIterator); - REGISTER_LONG_CONSTANT("CIT_CALL_TOSTRING", (long)CIT_CALL_TOSTRING, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("CIT_CATCH_GET_CHILD", (long)CIT_CATCH_GET_CHILD, CONST_CS | CONST_PERSISTENT); + REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "CALL_TOSTRING", CIT_CALL_TOSTRING); + REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "CATCH_GET_CHILD", CIT_CATCH_GET_CHILD); REGISTER_SPL_SUB_CLASS_EX(CachingRecursiveIterator, CachingIterator, spl_dual_it_new, spl_funcs_CachingRecursiveIterator); REGISTER_SPL_IMPLEMENTS(CachingRecursiveIterator, RecursiveIterator); diff --git a/ext/spl/spl_iterators.h b/ext/spl/spl_iterators.h index 3bfe91d949..3e0d0cba11 100755 --- a/ext/spl/spl_iterators.h +++ b/ext/spl/spl_iterators.h @@ -33,6 +33,7 @@ extern PHPAPI zend_class_entry *spl_ce_RecursiveIterator; extern PHPAPI zend_class_entry *spl_ce_RecursiveIteratorIterator; extern PHPAPI zend_class_entry *spl_ce_FilterIterator; +extern PHPAPI zend_class_entry *spl_ce_RecursiveFilterIterator; extern PHPAPI zend_class_entry *spl_ce_ParentIterator; extern PHPAPI zend_class_entry *spl_ce_SeekableIterator; extern PHPAPI zend_class_entry *spl_ce_LimitIterator; diff --git a/ext/spl/spl_observer.c b/ext/spl/spl_observer.c index 51baca8c15..aa8e602a57 100755 --- a/ext/spl/spl_observer.c +++ b/ext/spl/spl_observer.c @@ -4,7 +4,7 @@ +----------------------------------------------------------------------+ | Copyright (c) 1997-2005 The PHP Group | +----------------------------------------------------------------------+ - | This source file is subject to version 3.0 of the PHP license, | + | This source file is SplSubject to version 3.0 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_0.txt. | @@ -32,47 +32,232 @@ #include "spl_functions.h" #include "spl_engine.h" #include "spl_observer.h" +#include "spl_iterators.h" +#include "spl_array.h" -SPL_METHOD(Observer, update); -SPL_METHOD(Subject, attach); -SPL_METHOD(Subject, detach); -SPL_METHOD(Subject, notify); +SPL_METHOD(SplObserver, update); +SPL_METHOD(SplSubject, attach); +SPL_METHOD(SplSubject, detach); +SPL_METHOD(SplSubject, notify); static -ZEND_BEGIN_ARG_INFO(arginfo_Observer_update, 0) - ZEND_ARG_OBJ_INFO(0, subject, Subject, 0) +ZEND_BEGIN_ARG_INFO(arginfo_SplObserver_update, 0) + ZEND_ARG_OBJ_INFO(0, SplSubject, SplSubject, 0) ZEND_END_ARG_INFO(); -static zend_function_entry spl_funcs_Observer[] = { - SPL_ABSTRACT_ME(Observer, update, arginfo_Observer_update) +static zend_function_entry spl_funcs_SplObserver[] = { + SPL_ABSTRACT_ME(SplObserver, update, arginfo_SplObserver_update) {NULL, NULL, NULL} }; static -ZEND_BEGIN_ARG_INFO(arginfo_Subject_attach, 0) - ZEND_ARG_OBJ_INFO(0, observer, Observer, 0) +ZEND_BEGIN_ARG_INFO(arginfo_SplSubject_attach, 0) + ZEND_ARG_OBJ_INFO(0, SplObserver, SplObserver, 0) ZEND_END_ARG_INFO(); /*static -ZEND_BEGIN_ARG_INFO_EX(arginfo_Subject_notify, 0, 0, 1) - ZEND_ARG_OBJ_INFO(0, ignore, Observer, 1) +ZEND_BEGIN_ARG_INFO_EX(arginfo_SplSubject_notify, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, ignore, SplObserver, 1) ZEND_END_ARG_INFO();*/ -static zend_function_entry spl_funcs_Subject[] = { - SPL_ABSTRACT_ME(Subject, attach, arginfo_Subject_attach) - SPL_ABSTRACT_ME(Subject, detach, arginfo_Subject_attach) - SPL_ABSTRACT_ME(Subject, notify, NULL) +static zend_function_entry spl_funcs_SplSubject[] = { + SPL_ABSTRACT_ME(SplSubject, attach, arginfo_SplSubject_attach) + SPL_ABSTRACT_ME(SplSubject, detach, arginfo_SplSubject_attach) + SPL_ABSTRACT_ME(SplSubject, notify, NULL) {NULL, NULL, NULL} }; -PHPAPI zend_class_entry *spl_ce_Observer; -PHPAPI zend_class_entry *spl_ce_Subject; +PHPAPI zend_class_entry *spl_ce_SplObserver; +PHPAPI zend_class_entry *spl_ce_SplSubject; +PHPAPI zend_class_entry *spl_ce_SplObjectStorage; +PHPAPI zend_object_handlers spl_handler_SplObjectStorage; + +typedef struct _spl_SplObjectStorage { + zend_object std; + HashTable storage; + long index; + HashPosition pos; +} spl_SplObjectStorage; + +/* storage is an assoc aray of [zend_object_value]=>[zval*] */ + +void spl_SplOjectStorage_free_storage(void *object TSRMLS_DC) /* {{{ */ +{ + spl_SplObjectStorage *intern = (spl_SplObjectStorage *)object; + + zend_hash_destroy(intern->std.properties); + FREE_HASHTABLE(intern->std.properties); + + zend_hash_destroy(&intern->storage); + + efree(object); +} /* }}} */ + +static zend_object_value spl_object_storage_new_ex(zend_class_entry *class_type, spl_SplObjectStorage **obj, zval *orig TSRMLS_DC) /* {{{ */ +{ + zend_object_value retval; + spl_SplObjectStorage *intern; + zval *tmp; + + intern = emalloc(sizeof(spl_SplObjectStorage)); + memset(intern, 0, sizeof(spl_SplObjectStorage)); + intern->std.ce = class_type; + *obj = intern; + + ALLOC_HASHTABLE(intern->std.properties); + zend_hash_init(intern->std.properties, 0, NULL, ZVAL_PTR_DTOR, 0); + zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); + + zend_hash_init(&intern->storage, 0, NULL, ZVAL_PTR_DTOR, 0); + + retval.handle = zend_objects_store_put(intern, NULL, (zend_objects_free_object_storage_t) spl_SplOjectStorage_free_storage, NULL TSRMLS_CC); + retval.handlers = &spl_handler_SplObjectStorage; + return retval; +} +/* }}} */ + +/* {{{ spl_array_object_new */ +static zend_object_value spl_SplObjectStorage_new(zend_class_entry *class_type TSRMLS_DC) +{ + spl_SplObjectStorage *tmp; + return spl_object_storage_new_ex(class_type, &tmp, NULL TSRMLS_CC); +} +/* }}} */ + +/* {{{ proto void SplObjectStorage::attach($obj) + Attaches an object to the storage if not yet contained */ +SPL_METHOD(SplObjectStorage, attach) +{ + zval *obj; + spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) { + return; + } + + zend_hash_update(&intern->storage, (char*)&obj->value.obj, sizeof(obj->value.obj), &obj, sizeof(zval**), NULL); + obj->refcount++; +} /* }}} */ + +/* {{{ proto void SplObjectStorage::detach($obj) + Detaches an object from the storage */ +SPL_METHOD(SplObjectStorage, detach) +{ + zval *obj; + spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) { + return; + } + + zend_hash_del(&intern->storage, (char*)&obj->value.obj, sizeof(obj->value.obj)); + zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos); + intern->index = 0; +} /* }}} */ + +/* {{{ proto bool SplObjectStorage::contains($obj) + Determine whethe an object is contained in the storage */ +SPL_METHOD(SplObjectStorage, contains) +{ + zval *obj; + spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) { + return; + } + + RETURN_BOOL(zend_hash_exists(&intern->storage, (char*)&obj->value.obj, sizeof(obj->value.obj))); +} /* }}} */ + +/* {{{ proto int SplObjectStorage::count() + Determine number of objects in storage */ +SPL_METHOD(SplObjectStorage, count) +{ + spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + + RETURN_LONG(zend_hash_num_elements(&intern->storage)); +} /* }}} */ + +/* {{{ proto void SplObjectStorage::rewind() + */ +SPL_METHOD(SplObjectStorage, rewind) +{ + spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + + zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos); + intern->index = 0; +} /* }}} */ + +/* {{{ proto bool SplObjectStorage::valid() + */ +SPL_METHOD(SplObjectStorage, valid) +{ + spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + + RETURN_BOOL(zend_hash_has_more_elements_ex(&intern->storage, &intern->pos) == SUCCESS); +} /* }}} */ + +/* {{{ proto mixed SplObjectStorage::key() + */ +SPL_METHOD(SplObjectStorage, key) +{ + spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + + RETURN_LONG(intern->index); +} /* }}} */ + +/* {{{ proto mixed SplObjectStorage::current() + */ +SPL_METHOD(SplObjectStorage, current) +{ + zval **entry; + spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_hash_get_current_data_ex(&intern->storage, (void**)&entry, &intern->pos) == FAILURE) { + return; + } + RETVAL_ZVAL(*entry, 1, 0); +} /* }}} */ + +/* {{{ proto void SplObjectStorage::next() + */ +SPL_METHOD(SplObjectStorage, next) +{ + spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + + zend_hash_move_forward_ex(&intern->storage, &intern->pos); + intern->index++; +} /* }}} */ + +static +ZEND_BEGIN_ARG_INFO(arginfo_Object, 0) + ZEND_ARG_INFO(0, object 0) +ZEND_END_ARG_INFO(); + +static zend_function_entry spl_funcs_SplObjectStorage[] = { + SPL_ME(SplObjectStorage, attach, arginfo_Object, 0) + SPL_ME(SplObjectStorage, detach, arginfo_Object, 0) + SPL_ME(SplObjectStorage, contains, arginfo_Object, 0) + SPL_ME(SplObjectStorage, count, NULL, 0) + SPL_ME(SplObjectStorage, rewind, NULL, 0) + SPL_ME(SplObjectStorage, valid, NULL, 0) + SPL_ME(SplObjectStorage, key, NULL, 0) + SPL_ME(SplObjectStorage, current, NULL, 0) + SPL_ME(SplObjectStorage, next, NULL, 0) + {NULL, NULL, NULL} +}; /* {{{ PHP_MINIT_FUNCTION(spl_observer) */ PHP_MINIT_FUNCTION(spl_observer) { - REGISTER_SPL_INTERFACE(Observer); - REGISTER_SPL_INTERFACE(Subject); + REGISTER_SPL_INTERFACE(SplObserver); + REGISTER_SPL_INTERFACE(SplSubject); + + REGISTER_SPL_STD_CLASS_EX(SplObjectStorage, spl_SplObjectStorage_new, spl_funcs_SplObjectStorage); + memcpy(&spl_handler_SplObjectStorage, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + + REGISTER_SPL_IMPLEMENTS(SplObjectStorage, Countable); + REGISTER_SPL_IMPLEMENTS(SplObjectStorage, Iterator); return SUCCESS; } diff --git a/ext/spl/spl_observer.h b/ext/spl/spl_observer.h index 0394d6e922..d5cf4dc6a8 100755 --- a/ext/spl/spl_observer.h +++ b/ext/spl/spl_observer.h @@ -24,8 +24,9 @@ #include "php.h" #include "php_spl.h" -extern PHPAPI zend_class_entry *spl_ce_Observer; -extern PHPAPI zend_class_entry *spl_ce_Subject; +extern PHPAPI zend_class_entry *spl_ce_SplObserver; +extern PHPAPI zend_class_entry *spl_ce_SplSubject; +extern PHPAPI zend_class_entry *spl_ce_SplObjectStorage; PHP_MINIT_FUNCTION(spl_observer); diff --git a/ext/spl/tests/array_009.phpt b/ext/spl/tests/array_009.phpt index 5499caad69..fce2b42df2 100755 --- a/ext/spl/tests/array_009.phpt +++ b/ext/spl/tests/array_009.phpt @@ -20,7 +20,7 @@ class RecursiceArrayIterator extends ArrayIterator implements RecursiveIterator $array = array(1, 2 => array(21, 22 => array(221, 222), 23 => array(231)), 3); -$dir = new RecursiveIteratorIterator(new RecursiceArrayIterator($array), RIT_LEAVES_ONLY); +$dir = new RecursiveIteratorIterator(new RecursiceArrayIterator($array), RecursiveIteratorIterator::LEAVES_ONLY); foreach ($dir as $file) { print "$file\n"; diff --git a/ext/spl/tests/fileobject_001.phpt b/ext/spl/tests/fileobject_001.phpt index 056c1e17f7..cfd5a74ae6 100755 --- a/ext/spl/tests/fileobject_001.phpt +++ b/ext/spl/tests/fileobject_001.phpt @@ -7,7 +7,7 @@ $o = new FileObject(dirname(__FILE__) . '/fileobject_001a.txt'); var_dump($o->key()); var_dump($o->current()); -$o->setFlags(FO_DROP_NEW_LINE); +$o->setFlags(FileObject::DROP_NEW_LINE); var_dump($o->key()); var_dump($o->current()); var_dump($o->key()); @@ -32,7 +32,7 @@ foreach($o as $n => $l) echo "===B===\n"; $o = new FileObject(dirname(__FILE__) . '/fileobject_001b.txt'); -$o->setFlags(FO_DROP_NEW_LINE); +$o->setFlags(FileObject::DROP_NEW_LINE); foreach($o as $n => $l) { var_dump($n, $l); diff --git a/ext/spl/tests/iterator_002.phpt b/ext/spl/tests/iterator_002.phpt index b481a0e00f..d56a551c3f 100755 --- a/ext/spl/tests/iterator_002.phpt +++ b/ext/spl/tests/iterator_002.phpt @@ -38,7 +38,7 @@ class CrashIterator extends FilterIterator implements RecursiveIterator $array = array(1, 2 => array(21, 22 => array(221, 222), 23 => array(231)), 3); -$dir = new RecursiveIteratorIterator(new CrashIterator(new RecursiceArrayIterator($array)), RIT_LEAVES_ONLY); +$dir = new RecursiveIteratorIterator(new CrashIterator(new RecursiceArrayIterator($array)), RecursiveIteratorIterator::LEAVES_ONLY); foreach ($dir as $file) { print "$file\n"; diff --git a/ext/spl/tests/iterator_023.phpt b/ext/spl/tests/iterator_023.phpt index 46aa26ac71..8521fa4674 100755 --- a/ext/spl/tests/iterator_023.phpt +++ b/ext/spl/tests/iterator_023.phpt @@ -39,7 +39,7 @@ class RecursiveArrayIteratorIterator extends RecursiveIteratorIterator function __construct($it, $max_depth) { $this->max_depth = $max_depth; - parent::__construct($it, RIT_LEAVES_ONLY, RIT_CATCH_GET_CHILD); + parent::__construct($it, RecursiveIteratorIterator::LEAVES_ONLY, RecursiveIteratorIterator::CATCH_GET_CHILD); } function rewind() diff --git a/ext/spl/tests/observer_001.phpt b/ext/spl/tests/observer_001.phpt index 3b20e25bdc..e7d72b9e24 100755 --- a/ext/spl/tests/observer_001.phpt +++ b/ext/spl/tests/observer_001.phpt @@ -1,9 +1,9 @@ --TEST-- -SPL: Observer and Subject (empty notify) +SPL: SplObserver and SplSubject (empty notify) --FILE-- name = '$' . $name; } - function update(Subject $subject) + function update(SplSubject $subject) { echo $this->name . '->' . __METHOD__ . '(' . $subject->getName() . ");\n"; } @@ -23,7 +23,7 @@ class ObserverImpl implements Observer } } -class SubjectImpl implements Subject +class SubjectImpl implements SplSubject { protected $name = ''; protected $observers = array(); @@ -33,7 +33,7 @@ class SubjectImpl implements Subject $this->name = '$' . $name; } - function attach(Observer $observer) + function attach(SplObserver $observer) { echo '$sub->' . __METHOD__ . '(' . $observer->getName() . ");\n"; if (!in_array($observer, $this->observers)) @@ -42,7 +42,7 @@ class SubjectImpl implements Subject } } - function detach(Observer $observer) + function detach(SplObserver $observer) { echo '$sub->' . __METHOD__ . '(' . $observer->getName() . ");\n"; $idx = array_search($observer, $this->observers); diff --git a/ext/spl/tests/sxe_004.phpt b/ext/spl/tests/sxe_004.phpt index 98865955ad..487de45071 100755 --- a/ext/spl/tests/sxe_004.phpt +++ b/ext/spl/tests/sxe_004.phpt @@ -77,7 +77,7 @@ class SXETest extends SimpleXMLIterator } $sxe = new SXETest($xml); -$rit = new RecursiveIteratorIterator($sxe, RIT_SELF_FIRST); +$rit = new RecursiveIteratorIterator($sxe, RecursiveIteratorIterator::SELF_FIRST); foreach($rit as $data) { var_dump(get_class($data)); @@ -145,3 +145,62 @@ SXETest::next SXETest::valid SXETest::valid ===DONE=== +--UEXPECTF-- +SXETest::rewind +SXETest::valid +SXETest::hasChildren +SXETest::valid +SXETest::current +unicode(7) "SXETest" +unicode(10) "Bla bla 1." +SXETest::getChildren +SXETest::rewind +SXETest::valid +SXETest::hasChildren +SXETest::valid +SXETest::current +unicode(7) "SXETest" +unicode(28) "Here we have some text data." +SXETest::getChildren +SXETest::rewind +SXETest::valid +SXETest::hasChildren +SXETest::valid +SXETest::current +unicode(7) "SXETest" +unicode(19) "And here some more." +SXETest::getChildren +SXETest::rewind +SXETest::valid +SXETest::hasChildren +SXETest::valid +SXETest::current +unicode(7) "SXETest" +unicode(15) "Wow once again." +SXETest::next +SXETest::valid +SXETest::next +SXETest::valid +SXETest::next +SXETest::valid +SXETest::next +SXETest::valid +SXETest::hasChildren +SXETest::valid +SXETest::current +unicode(7) "SXETest" +unicode(10) "Bla bla 2." +SXETest::getChildren +SXETest::rewind +SXETest::valid +SXETest::hasChildren +SXETest::valid +SXETest::current +unicode(7) "SXETest" +unicode(7) "Foo Bar" +SXETest::next +SXETest::valid +SXETest::next +SXETest::valid +SXETest::valid +===DONE=== -- 2.40.0