helly Tue Jul 22 22:54:15 2008 UTC Added files: /php-src/ext/spl/internal multipleiterator.inc /php-src/ext/spl/tests multiple_iterator_001.phpt
Removed files: /php-src/ext/spl/examples multipleiterator.inc Modified files: /php-src/ext/spl php_spl.c spl_iterators.c spl_iterators.h spl_observer.c spl_observer.h /php-src/ext/spl/internal recursivetreeiterator.inc Log: - Add MultipleIterator (Arnaud, Marcus)
http://cvs.php.net/viewvc.cgi/php-src/ext/spl/php_spl.c?r1=1.136&r2=1.137&diff_format=u Index: php-src/ext/spl/php_spl.c diff -u php-src/ext/spl/php_spl.c:1.136 php-src/ext/spl/php_spl.c:1.137 --- php-src/ext/spl/php_spl.c:1.136 Sun Jul 13 21:38:58 2008 +++ php-src/ext/spl/php_spl.c Tue Jul 22 22:54:14 2008 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: php_spl.c,v 1.136 2008/07/13 21:38:58 helly Exp $ */ +/* $Id: php_spl.c,v 1.137 2008/07/22 22:54:14 helly Exp $ */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -150,14 +150,6 @@ SPL_ADD_CLASS(AppendIterator, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(ArrayIterator, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(ArrayObject, z_list, sub, allow, ce_flags); \ - SPL_ADD_CLASS(SplDoublyLinkedList, z_list, sub, allow, ce_flags); \ - SPL_ADD_CLASS(SplQueue, z_list, sub, allow, ce_flags); \ - SPL_ADD_CLASS(SplStack, z_list, sub, allow, ce_flags); \ - SPL_ADD_CLASS(SplHeap, z_list, sub, allow, ce_flags); \ - SPL_ADD_CLASS(SplMinHeap, z_list, sub, allow, ce_flags); \ - SPL_ADD_CLASS(SplMaxHeap, z_list, sub, allow, ce_flags); \ - SPL_ADD_CLASS(SplPriorityQueue, z_list, sub, allow, ce_flags); \ - SPL_ADD_CLASS(SplFixedArray, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(BadFunctionCallException, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(BadMethodCallException, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(CachingIterator, z_list, sub, allow, ce_flags); \ @@ -174,6 +166,7 @@ SPL_ADD_CLASS(LengthException, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(LimitIterator, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(LogicException, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(MultipleIterator, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(NoRewindIterator, 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); \ @@ -188,14 +181,23 @@ SPL_ADD_CLASS(RecursiveIterator, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(RecursiveIteratorIterator, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(RecursiveRegexIterator, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(RecursiveTreeIterator, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(RegexIterator, 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(SplDoublyLinkedList, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(SplFileInfo, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(SplFileObject, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(SplFixedArray, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(SplHeap, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(SplMinHeap, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(SplMaxHeap, 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(SplPriorityQueue, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(SplQueue, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(SplStack, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(SplSubject, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(SplTempFileObject, z_list, sub, allow, ce_flags); \ SPL_ADD_CLASS(UnderflowException, z_list, sub, allow, ce_flags); \ http://cvs.php.net/viewvc.cgi/php-src/ext/spl/spl_iterators.c?r1=1.173&r2=1.174&diff_format=u Index: php-src/ext/spl/spl_iterators.c diff -u php-src/ext/spl/spl_iterators.c:1.173 php-src/ext/spl/spl_iterators.c:1.174 --- php-src/ext/spl/spl_iterators.c:1.173 Sat Jul 19 19:45:25 2008 +++ php-src/ext/spl/spl_iterators.c Tue Jul 22 22:54:14 2008 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: spl_iterators.c,v 1.173 2008/07/19 19:45:25 colder Exp $ */ +/* $Id: spl_iterators.c,v 1.174 2008/07/22 22:54:14 helly Exp $ */ #ifdef HAVE_CONFIG_H # include "config.h" @@ -35,6 +35,7 @@ #include "spl_directory.h" #include "spl_array.h" #include "spl_exceptions.h" +#include "spl_observer.h" #include "ext/standard/php_smart_str.h" #ifdef accept http://cvs.php.net/viewvc.cgi/php-src/ext/spl/spl_iterators.h?r1=1.45&r2=1.46&diff_format=u Index: php-src/ext/spl/spl_iterators.h diff -u php-src/ext/spl/spl_iterators.h:1.45 php-src/ext/spl/spl_iterators.h:1.46 --- php-src/ext/spl/spl_iterators.h:1.45 Sat Jul 19 15:43:35 2008 +++ php-src/ext/spl/spl_iterators.h Tue Jul 22 22:54:14 2008 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: spl_iterators.h,v 1.45 2008/07/19 15:43:35 helly Exp $ */ +/* $Id: spl_iterators.h,v 1.46 2008/07/22 22:54:14 helly Exp $ */ #ifndef SPL_ITERATORS_H #define SPL_ITERATORS_H @@ -35,6 +35,7 @@ extern PHPAPI zend_class_entry *spl_ce_RecursiveIterator; extern PHPAPI zend_class_entry *spl_ce_RecursiveIteratorIterator; +extern PHPAPI zend_class_entry *spl_ce_RecursiveTreeIterator; extern PHPAPI zend_class_entry *spl_ce_FilterIterator; extern PHPAPI zend_class_entry *spl_ce_RecursiveFilterIterator; extern PHPAPI zend_class_entry *spl_ce_ParentIterator; http://cvs.php.net/viewvc.cgi/php-src/ext/spl/spl_observer.c?r1=1.23&r2=1.24&diff_format=u Index: php-src/ext/spl/spl_observer.c diff -u php-src/ext/spl/spl_observer.c:1.23 php-src/ext/spl/spl_observer.c:1.24 --- php-src/ext/spl/spl_observer.c:1.23 Mon Jan 28 22:43:21 2008 +++ php-src/ext/spl/spl_observer.c Tue Jul 22 22:54:14 2008 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: spl_observer.c,v 1.23 2008/01/28 22:43:21 helly Exp $ */ +/* $Id: spl_observer.c,v 1.24 2008/07/22 22:54:14 helly Exp $ */ #ifdef HAVE_CONFIG_H # include "config.h" @@ -73,6 +73,8 @@ PHPAPI zend_class_entry *spl_ce_SplObserver; PHPAPI zend_class_entry *spl_ce_SplSubject; PHPAPI zend_class_entry *spl_ce_SplObjectStorage; +PHPAPI zend_class_entry *spl_ce_MultipleIterator; + PHPAPI zend_object_handlers spl_handler_SplObjectStorage; typedef struct _spl_SplObjectStorage { /* {{{ */ @@ -80,6 +82,7 @@ HashTable storage; long index; HashPosition pos; + long flags; } spl_SplObjectStorage; /* }}} */ /* {{{ storage is an assoc aray of [zend_object_value]=>[zval *obj, zval *inf] */ @@ -595,6 +598,298 @@ ZEND_ARG_INFO(0, info) ZEND_END_ARG_INFO() +typedef enum { + MIT_NEED_ANY = 0, + MIT_NEED_ALL = 1, + MIT_KEYS_NUMERIC = 0, + MIT_KEYS_ASSOC = 2 +} MultipleIteratorFlags; + +#define SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT 1 +#define SPL_MULTIPLE_ITERATOR_GET_ALL_KEY 2 + +/* {{{ proto void MultipleIterator::__construct([int flags = MIT_NEED_ALL|MIT_KEYS_NUMERIC]) U + Iterator that iterates over several iterators one after the other */ +SPL_METHOD(MultipleIterator, __construct) +{ + spl_SplObjectStorage *intern; + long flags = MIT_NEED_ALL|MIT_KEYS_NUMERIC; + + php_set_error_handling(EH_THROW, spl_ce_InvalidArgumentException TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flags) == FAILURE) { + php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC); + return; + } + + php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC); + + intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + intern->flags = flags; +} +/* }}} */ + +/* {{{ proto int MultipleIterator::getFlags() U + Return current flags */ +SPL_METHOD(MultipleIterator, getFlags) +{ + spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + RETURN_LONG(intern->flags); +} +/* }}} */ + +/* {{{ proto int MultipleIterator::setFlags(int flags) U + Set flags */ +SPL_METHOD(MultipleIterator, setFlags) +{ + spl_SplObjectStorage *intern; + intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &intern->flags) == FAILURE) { + return; + } +} +/* }}} */ + +/* {{{ proto void attachIterator(Iterator iterator[, mixed info]) throws InvalidArgumentException U + Attach a new iterator */ +SPL_METHOD(MultipleIterator, attachIterator) +{ + spl_SplObjectStorage *intern; + zval *iterator = NULL, *info = NULL; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|z!", &iterator, zend_ce_iterator, &info) == FAILURE) { + return; + } + + intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (info != NULL) { + spl_SplObjectStorageElement *element; + zval compare_result; + + if (Z_TYPE_P(info) != IS_LONG && Z_TYPE_P(info) != IS_STRING && Z_TYPE_P(info) != IS_UNICODE) { + zend_throw_exception(spl_ce_InvalidArgumentException, "Info must be NULL, integer or string", 0 TSRMLS_CC); + return; + } + + zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos); + while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS) { + is_identical_function(&compare_result, info, element->inf TSRMLS_CC); + if (Z_LVAL(compare_result)) { + zend_throw_exception(spl_ce_InvalidArgumentException, "Key duplication error", 0 TSRMLS_CC); + return; + } + zend_hash_move_forward_ex(&intern->storage, &intern->pos); + } + } + + spl_object_storage_attach(intern, iterator, info TSRMLS_CC); +} +/* }}} */ + +/* {{{ proto void MultipleIterator::rewind() U + Rewind all attached iterator instances */ +SPL_METHOD(MultipleIterator, rewind) +{ + spl_SplObjectStorage *intern; + spl_SplObjectStorageElement *element; + zval *it; + + intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + + zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos); + while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS && !EG(exception)) { + it = element->obj; + zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_rewind, "rewind", NULL); + zend_hash_move_forward_ex(&intern->storage, &intern->pos); + } +} +/* }}} */ + +/* {{{ proto void MultipleIterator::next() U + Move all attached iterator instances forward */ +SPL_METHOD(MultipleIterator, next) +{ + spl_SplObjectStorage *intern; + spl_SplObjectStorageElement *element; + zval *it; + + intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + + zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos); + while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS && !EG(exception)) { + it = element->obj; + zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_next, "next", NULL); + zend_hash_move_forward_ex(&intern->storage, &intern->pos); + } +} +/* }}} */ + +/* {{{ proto bool MultipleIterator::valid() U + Return whether all or one sub iterator is valid depending on flags */ +SPL_METHOD(MultipleIterator, valid) +{ + spl_SplObjectStorage *intern; + spl_SplObjectStorageElement *element; + zval *it, *retval = NULL; + long expect, valid; + + intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (!zend_hash_num_elements(&intern->storage)) { + RETURN_FALSE; + } + + expect = (intern->flags & MIT_NEED_ALL) ? 1 : 0; + + zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos); + while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS && !EG(exception)) { + it = element->obj; + zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_valid, "valid", &retval); + + if (retval) { + valid = Z_LVAL_P(retval); + zval_ptr_dtor(&retval); + } else { + valid = 0; + } + + if (expect != valid) { + RETURN_BOOL(!expect); + } + + zend_hash_move_forward_ex(&intern->storage, &intern->pos); + } + + RETURN_BOOL(expect); +} +/* }}} */ + +static void spl_multiple_iterator_get_all(spl_SplObjectStorage *intern, int get_type, zval *return_value TSRMLS_DC) /* {{{ */ +{ + spl_SplObjectStorageElement *element; + zval *it, *retval = NULL; + int valid = 1, num_elements; + + num_elements = zend_hash_num_elements(&intern->storage); + if (num_elements < 1) { + RETURN_FALSE; + } + + array_init_size(return_value, num_elements); + + zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos); + while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS && !EG(exception)) { + it = element->obj; + zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_valid, "valid", &retval); + + if (retval) { + valid = Z_LVAL_P(retval); + zval_ptr_dtor(&retval); + } else { + valid = 0; + } + + if (valid) { + if (SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT == get_type) { + zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_current, "current", &retval); + } else { + zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_key, "key", &retval); + } + if (!retval) { + zend_throw_exception(spl_ce_RuntimeException, "Failed to call sub iterator method", 0 TSRMLS_CC); + return; + } + } else if (intern->flags & MIT_NEED_ALL) { + if (SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT == get_type) { + zend_throw_exception(spl_ce_RuntimeException, "Called current() with non valid sub iterator", 0 TSRMLS_CC); + } else { + zend_throw_exception(spl_ce_RuntimeException, "Called key() with non valid sub iterator", 0 TSRMLS_CC); + } + return; + } else { + ALLOC_INIT_ZVAL(retval); + } + + if (intern->flags & MIT_KEYS_ASSOC) { + switch (Z_TYPE_P(element->inf)) { + case IS_LONG: + add_index_zval(return_value, Z_LVAL_P(element->inf), retval); + break; + case IS_STRING: + case IS_UNICODE: + add_u_assoc_zval_ex(return_value, Z_TYPE_P(element->inf), Z_UNIVAL_P(element->inf), Z_UNILEN_P(element->inf)+1U, retval); + break; + default: + zval_ptr_dtor(&retval); + zend_throw_exception(spl_ce_InvalidArgumentException, "Sub-Iterator is associated with NULL", 0 TSRMLS_CC); + return; + } + } else { + add_next_index_zval(return_value, retval); + } + + zend_hash_move_forward_ex(&intern->storage, &intern->pos); + } +} +/* }}} */ + +/* {{{ proto array current() throws RuntimeException throws InvalidArgumentException U + Return an array of all registered Iterator instances current() result */ +SPL_METHOD(MultipleIterator, current) +{ + spl_SplObjectStorage *intern; + intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + + spl_multiple_iterator_get_all(intern, SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT, return_value TSRMLS_CC); +} +/* }}} */ + +/* {{{ proto array MultipleIterator::key() U + Return an array of all registered Iterator instances key() result */ +SPL_METHOD(MultipleIterator, key) +{ + spl_SplObjectStorage *intern; + intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + + spl_multiple_iterator_get_all(intern, SPL_MULTIPLE_ITERATOR_GET_ALL_KEY, return_value TSRMLS_CC); +} +/* }}} */ + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_MultipleIterator_attachIterator, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0) + ZEND_ARG_INFO(0, infos) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_MultipleIterator_detachIterator, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_MultipleIterator_containsIterator, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0) +ZEND_END_ARG_INFO(); + +static const zend_function_entry spl_funcs_MultipleIterator[] = { + SPL_ME(MultipleIterator, __construct, NULL, 0) + SPL_ME(MultipleIterator, getFlags, NULL, 0) + SPL_ME(MultipleIterator, setFlags, NULL, 0) + SPL_ME(MultipleIterator, attachIterator, arginfo_MultipleIterator_attachIterator, 0) + SPL_MA(MultipleIterator, detachIterator, SplObjectStorage, detach, arginfo_MultipleIterator_detachIterator, 0) + SPL_MA(MultipleIterator, containsIterator, SplObjectStorage, contains, arginfo_MultipleIterator_containsIterator, 0) + SPL_MA(MultipleIterator, countIterators, SplObjectStorage, count, NULL, 0) + /* Iterator */ + SPL_ME(MultipleIterator, rewind, NULL, 0) + SPL_ME(MultipleIterator, valid, NULL, 0) + SPL_ME(MultipleIterator, key, NULL, 0) + SPL_ME(MultipleIterator, current, NULL, 0) + SPL_ME(MultipleIterator, next, NULL, 0) + {NULL, NULL, NULL} +}; + static const zend_function_entry spl_funcs_SplObjectStorage[] = { SPL_ME(SplObjectStorage, attach, arginfo_attach, 0) SPL_ME(SplObjectStorage, detach, arginfo_Object, 0) @@ -635,6 +930,14 @@ REGISTER_SPL_IMPLEMENTS(SplObjectStorage, Serializable); REGISTER_SPL_IMPLEMENTS(SplObjectStorage, ArrayAccess); + REGISTER_SPL_STD_CLASS_EX(MultipleIterator, spl_SplObjectStorage_new, spl_funcs_MultipleIterator); + REGISTER_SPL_ITERATOR(MultipleIterator); + + REGISTER_SPL_CLASS_CONST_LONG(MultipleIterator, "MIT_NEED_ANY", MIT_NEED_ANY); + REGISTER_SPL_CLASS_CONST_LONG(MultipleIterator, "MIT_NEED_ALL", MIT_NEED_ALL); + REGISTER_SPL_CLASS_CONST_LONG(MultipleIterator, "MIT_KEYS_NUMERIC", MIT_KEYS_NUMERIC); + REGISTER_SPL_CLASS_CONST_LONG(MultipleIterator, "MIT_KEYS_ASSOC", MIT_KEYS_ASSOC); + return SUCCESS; } /* }}} */ http://cvs.php.net/viewvc.cgi/php-src/ext/spl/spl_observer.h?r1=1.7&r2=1.8&diff_format=u Index: php-src/ext/spl/spl_observer.h diff -u php-src/ext/spl/spl_observer.h:1.7 php-src/ext/spl/spl_observer.h:1.8 --- php-src/ext/spl/spl_observer.h:1.7 Mon Dec 31 07:12:15 2007 +++ php-src/ext/spl/spl_observer.h Tue Jul 22 22:54:15 2008 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: spl_observer.h,v 1.7 2007/12/31 07:12:15 sebastian Exp $ */ +/* $Id: spl_observer.h,v 1.8 2008/07/22 22:54:15 helly Exp $ */ #ifndef SPL_OBSERVER_H #define SPL_OBSERVER_H @@ -27,6 +27,7 @@ extern PHPAPI zend_class_entry *spl_ce_SplObserver; extern PHPAPI zend_class_entry *spl_ce_SplSubject; extern PHPAPI zend_class_entry *spl_ce_SplObjectStorage; +extern PHPAPI zend_class_entry *spl_ce_MultipleIterator; PHP_MINIT_FUNCTION(spl_observer); http://cvs.php.net/viewvc.cgi/php-src/ext/spl/internal/recursivetreeiterator.inc?r1=1.2&r2=1.3&diff_format=u Index: php-src/ext/spl/internal/recursivetreeiterator.inc diff -u php-src/ext/spl/internal/recursivetreeiterator.inc:1.2 php-src/ext/spl/internal/recursivetreeiterator.inc:1.3 --- php-src/ext/spl/internal/recursivetreeiterator.inc:1.2 Sat Jul 19 15:48:07 2008 +++ php-src/ext/spl/internal/recursivetreeiterator.inc Tue Jul 22 22:54:15 2008 @@ -1,7 +1,7 @@ <?php /** @file recursivetreeiterator.inc - * @ingroup Examples + * @ingroup SPL * @brief class RecursiveTreeIterator * @author Marcus Boerger, Johannes Schlueter * @date 2005 http://cvs.php.net/viewvc.cgi/php-src/ext/spl/internal/multipleiterator.inc?view=markup&rev=1.1 Index: php-src/ext/spl/internal/multipleiterator.inc +++ php-src/ext/spl/internal/multipleiterator.inc <?php /** @file multipleiterator.inc * @ingroup SPL * @brief class MultipleIterator * @author Johannes Schlueter * @author Marcus Boerger * @date 2008 * * SPL - Standard PHP Library */ /** @ingroup SPL * @brief Iterator that iterates over several iterators one after the other * @author Johannes Schlueter * @author Marcus Boerger * @version 1.0 * @since PHP 5.3 */ class MultipleIterator implements Iterator { /** Inner Iterators */ private $iterators; /** Flags: const MIT_* */ private $flags; /** do not require all sub iterators to be valid in iteration */ const MIT_NEED_ANY = 0; /** require all sub iterators to be valid in iteration */ const MIT_NEED_ALL = 1; /** keys are created from sub iterators position */ const MIT_KEYS_NUMERIC = 0; /** keys are created from sub iterators associated infromation */ const MIT_KEYS_ASSOC = 2; /** Construct a new empty MultipleIterator * @param flags MIT_* flags */ public function __construct($flags = self::MIT_NEED_ALL|self::MIT_KEYS_NUMERIC) { $this->iterators = new SplObjectStorage(); $this->flags = $flags; } /** @return current flags MIT_* */ public function getFlags() { return $this->flags; } /** @param $flags new flags. */ public function setFlags($flags) { $this->flags = $flags; } /** @param $iter new Iterator to attach. * @param $inf associative info forIteraotr, must be NULL, integer or string * * @throws IllegalValueException if a inf is none of NULL, integer or string * @throws IllegalValueException if a inf is already an associated info */ public function attachIterator(Iterator $iter, $inf = NULL) { if (!is_null($inf)) { if (!is_int($inf) && !is_string($inf)) { throw new IllegalValueException('Inf must be NULL, integer or string'); } foreach($this->iterators as $iter) { if ($inf == $this->iterators->getInfo()) { throw new IllegalValueException('Key duplication error'); } } } $this->iterators->attach($iter, $inf); } /** @param $iter attached Iterator that should be detached. */ public function detachIterator(Iterator $iter) { $this->iterators->detach($iter); } /** @param $iter Iterator to check * @return whether $iter is attached or not */ public function containsIterator(Iterator $iter) { return $this->iterator->contains($iter); } /** @return number of attached Iterator instances. */ public function countIterators() { return $this->iterators->count(); } /** Rewind all attached Iterator instances. */ public function rewind() { foreach($this->iterators as $iter) { $iter->rewind(); } } /** * @return whether all or one sub iterator is valid depending on flags. * In mode MIT_NEED_ALL we expect all sub iterators to be valid and * return flase on the first non valid one. If that flag is not set we * return true on the first valid sub iterator found. If no Iterator * is attached, we always return false. */ public function valid() { if (!sizeof($this->iterators)) { return false; } // The following code is an optimized version that executes as few // valid() calls as necessary and that only checks the flags once. $expect = $this->flags & self::MIT_NEED_ALL ? true : false; foreach($this->iterators as $iter) { if ($expect != $iter->valid()) { return !$expect; } } return $expect; } /** Move all attached Iterator instances forward. That is invoke * their next() method regardless of their state. */ public function next() { foreach($this->iterators as $iter) { $iter->next(); } } /** @return false if no sub Iterator is attached and an array of * all registered Iterator instances current() result. * @throws RuntimeException if mode MIT_NEED_ALL is set and at least one * attached Iterator is not valid(). * @throws IllegalValueException if a key is NULL and MIT_KEYS_ASSOC is set. */ public function current() { if (!sizeof($this->iterators)) { return false; } $retval = array(); foreach($this->iterators as $iter) { if ($it->valid()) { if ($this->flags & self::MIT_KEYS_ASSOC) { $key = $this->iterators->getInfo(); if (is_null($key)) { throw new IllegalValueException('Sub-Iterator is associated with NULL'); } $retval[$key] = $iter->current(); } else { $retval[] = $iter->current(); } } else if ($this->flags & self::MIT_NEED_ALL) { throw new RuntimeException('Called current() with non valid sub iterator'); } else { $retval[] = NULL; } } return $retval; } /** @return false if no sub Iterator is attached and an array of * all registered Iterator instances key() result. * @throws LogicException if mode MIT_NEED_ALL is set and at least one * attached Iterator is not valid(). */ public function key() { if (!sizeof($this->iterators)) { return false; } $retval = array(); foreach($this->iterators as $iter) { if ($it->valid()) { $retval[] = $iter->key(); } else if ($this->flags & self::MIT_NEED_ALL) { throw new LogicException('Called key() with non valid sub iterator'); } else { $retval[] = NULL; } } return $retval; } } http://cvs.php.net/viewvc.cgi/php-src/ext/spl/tests/multiple_iterator_001.phpt?view=markup&rev=1.1 Index: php-src/ext/spl/tests/multiple_iterator_001.phpt +++ php-src/ext/spl/tests/multiple_iterator_001.phpt --TEST-- SPL: MultipleIterator --FILE-- <?php $iter1 = new ArrayIterator(array(1,2,3)); $iter2 = new ArrayIterator(array(1,2)); $iter3 = new ArrayIterator(array(new stdClass(),"string",3)); $m = new MultipleIterator(); echo "-- Default flags, no iterators --\n"; foreach($m as $value) { var_dump($value); } var_dump($m->current()); $m->attachIterator($iter1); $m->attachIterator($iter2); $m->attachIterator($iter3); echo "-- Default flags, MultipleIterator::MIT_NEED_ALL | MultipleIterator::MIT_KEYS_NUMERIC --\n"; var_dump($m->getFlags() === (MultipleIterator::MIT_NEED_ALL | MultipleIterator::MIT_KEYS_NUMERIC)); foreach($m as $value) { var_dump($m->key(), $value); } try { $m->current(); } catch(RuntimeException $e) { echo "RuntimeException thrown: " . $e->getMessage() . "\n"; } try { $m->key(); } catch(RuntimeException $e) { echo "RuntimeException thrown: " . $e->getMessage() . "\n"; } echo "-- Flags = MultipleIterator::MIT_NEED_ANY | MultipleIterator::MIT_KEYS_NUMERIC --\n"; $m->setFlags(MultipleIterator::MIT_NEED_ANY | MultipleIterator::MIT_KEYS_NUMERIC); var_dump($m->getFlags() === (MultipleIterator::MIT_NEED_ANY | MultipleIterator::MIT_KEYS_NUMERIC)); foreach($m as $value) { var_dump($m->key(), $value); } echo "-- Default flags, added element --\n"; $m->setFlags(MultipleIterator::MIT_NEED_ALL | MultipleIterator::MIT_KEYS_NUMERIC); $iter2[] = 3; foreach($m as $value) { var_dump($m->key(), $value); } echo "-- Flags |= MultipleIterator::MIT_KEYS_ASSOC, with iterator associated with NULL --\n"; $m->setFlags(MultipleIterator::MIT_NEED_ALL | MultipleIterator::MIT_KEYS_ASSOC); $m->rewind(); try { $m->current(); } catch(InvalidArgumentException $e) { echo "InvalidArgumentException thrown: " . $e->getMessage() . "\n"; } echo "-- Flags |= MultipleIterator::MIT_KEYS_ASSOC --\n"; $m->attachIterator($iter1, "iter1"); $m->attachIterator($iter2, b"iter2"); $m->attachIterator($iter3, 3); foreach($m as $value) { var_dump($m->key(), $value); } echo "-- Associate with invalid value --\n"; try { $m->attachIterator($iter3, new stdClass()); } catch(InvalidArgumentException $e) { echo "InvalidArgumentException thrown: " . $e->getMessage() . "\n"; } echo "-- Associate with duplicate value --\n"; try { $m->attachIterator($iter3, "iter1"); } catch(InvalidArgumentException $e) { echo "InvalidArgumentException thrown: " . $e->getMessage() . "\n"; } echo "-- Count, contains, detach, count, contains, iterate --\n"; var_dump($m->countIterators()); var_dump($m->containsIterator($iter2)); var_dump($m->detachIterator($iter2)); var_dump($m->countIterators()); var_dump($m->containsIterator($iter2)); foreach($m as $value) { var_dump($m->key(), $value); } ?> --EXPECTF-- -- Default flags, no iterators -- bool(false) -- Default flags, MultipleIterator::MIT_NEED_ALL | MultipleIterator::MIT_KEYS_NUMERIC -- bool(true) array(3) { [0]=> int(0) [1]=> int(0) [2]=> int(0) } array(3) { [0]=> int(1) [1]=> int(1) [2]=> object(stdClass)#%d (0) { } } array(3) { [0]=> int(1) [1]=> int(1) [2]=> int(1) } array(3) { [0]=> int(2) [1]=> int(2) [2]=> unicode(6) "string" } RuntimeException thrown: Called current() with non valid sub iterator RuntimeException thrown: Called key() with non valid sub iterator -- Flags = MultipleIterator::MIT_NEED_ANY | MultipleIterator::MIT_KEYS_NUMERIC -- bool(true) array(3) { [0]=> int(0) [1]=> int(0) [2]=> int(0) } array(3) { [0]=> int(1) [1]=> int(1) [2]=> object(stdClass)#%d (0) { } } array(3) { [0]=> int(1) [1]=> int(1) [2]=> int(1) } array(3) { [0]=> int(2) [1]=> int(2) [2]=> unicode(6) "string" } array(3) { [0]=> int(2) [1]=> NULL [2]=> int(2) } array(3) { [0]=> int(3) [1]=> NULL [2]=> int(3) } -- Default flags, added element -- array(3) { [0]=> int(0) [1]=> int(0) [2]=> int(0) } array(3) { [0]=> int(1) [1]=> int(1) [2]=> object(stdClass)#%d (0) { } } array(3) { [0]=> int(1) [1]=> int(1) [2]=> int(1) } array(3) { [0]=> int(2) [1]=> int(2) [2]=> unicode(6) "string" } array(3) { [0]=> int(2) [1]=> int(2) [2]=> int(2) } array(3) { [0]=> int(3) [1]=> int(3) [2]=> int(3) } -- Flags |= MultipleIterator::MIT_KEYS_ASSOC, with iterator associated with NULL -- InvalidArgumentException thrown: Sub-Iterator is associated with NULL -- Flags |= MultipleIterator::MIT_KEYS_ASSOC -- array(3) { [u"iter1"]=> int(0) ["iter2"]=> int(0) [3]=> int(0) } array(3) { [u"iter1"]=> int(1) ["iter2"]=> int(1) [3]=> object(stdClass)#%d (0) { } } array(3) { [u"iter1"]=> int(1) ["iter2"]=> int(1) [3]=> int(1) } array(3) { [u"iter1"]=> int(2) ["iter2"]=> int(2) [3]=> unicode(6) "string" } array(3) { [u"iter1"]=> int(2) ["iter2"]=> int(2) [3]=> int(2) } array(3) { [u"iter1"]=> int(3) ["iter2"]=> int(3) [3]=> int(3) } -- Associate with invalid value -- InvalidArgumentException thrown: Info must be NULL, integer or string -- Associate with duplicate value -- InvalidArgumentException thrown: Key duplication error -- Count, contains, detach, count, contains, iterate -- int(3) bool(true) NULL int(2) bool(false) array(2) { [u"iter1"]=> int(0) [3]=> int(0) } array(2) { [u"iter1"]=> int(1) [3]=> object(stdClass)#%d (0) { } } array(2) { [u"iter1"]=> int(1) [3]=> int(1) } array(2) { [u"iter1"]=> int(2) [3]=> unicode(6) "string" } array(2) { [u"iter1"]=> int(2) [3]=> int(2) } array(2) { [u"iter1"]=> int(3) [3]=> int(3) }
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php