From: Marcus Boerger Date: Sun, 18 Sep 2005 11:34:36 +0000 (+0000) Subject: - Move RecursiveArrayIterator into .c X-Git-Tag: RELEASE_0_9_0~192 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=445e382454a46ab68e651178f1bb56da2bdfe7f8;p=php - Move RecursiveArrayIterator into .c - Add ability to control iterator class of ArrayObject - Implement option to make CachingIterator cache all read elements - Implement ArrayAccess to CachingIterator to access cached elements - Update docu - Update tests --- diff --git a/ext/spl/examples/recursivearrayiterator.inc b/ext/spl/internal/recursivearrayiterator.inc similarity index 98% rename from ext/spl/examples/recursivearrayiterator.inc rename to ext/spl/internal/recursivearrayiterator.inc index 305e54cad9..1b4497afd8 100755 --- a/ext/spl/examples/recursivearrayiterator.inc +++ b/ext/spl/internal/recursivearrayiterator.inc @@ -9,7 +9,7 @@ * SPL - Standard PHP Library */ -/** @ingroup Examples +/** @ingroup SPL * @brief A recursive array iterator * @author Marcus Boerger * @version 1.0 diff --git a/ext/spl/php_spl.c b/ext/spl/php_spl.c index 6ac52f3c81..4bb47ef790 100755 --- a/ext/spl/php_spl.c +++ b/ext/spl/php_spl.c @@ -175,6 +175,7 @@ PHP_FUNCTION(class_implements) 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(RecursiveArrayIterator, 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); \ diff --git a/ext/spl/spl.php b/ext/spl/spl.php index 17c5f6f7f8..ae6d14bdd2 100755 --- a/ext/spl/spl.php +++ b/ext/spl/spl.php @@ -67,6 +67,7 @@ * * - class ArrayObject implements IteratorAggregate * - class ArrayIterator implements Iterator + * - class RecursiveArrayIterator extends ArrayIterator implements RecursiveIterator * * As the above suggest an ArrayObject creates an ArrayIterator when it comes to * iteration (e.g. ArrayObject instance used inside foreach). @@ -511,9 +512,9 @@ 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; + const STD_PROP_LIST = 0x00000001; /** Array indices can be accessed as properties in read/write */ - const ARRAY_AS_PROPS = 0x00000002; + const ARRAY_AS_PROPS = 0x00000002; /** Construct a new array iterator from anything that has a hash table. * That is any Array or Object. @@ -521,7 +522,7 @@ class ArrayObject implements IteratorAggregate, ArrayAccess, Countable * @param $array the array to use. * @param $flags see setFlags(). */ - function __construct($array, $flags = 0); + function __construct($array, $flags = 0, $iterator_class = "ArrayIterator"); /** Set behavior flags. * diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c index 9c80841afa..be51aa81c7 100755 --- a/ext/spl/spl_array.c +++ b/ext/spl/spl_array.c @@ -35,119 +35,22 @@ #include "spl_array.h" #include "spl_exceptions.h" -SPL_METHOD(Array, __construct); -SPL_METHOD(Array, getIterator); -SPL_METHOD(Array, rewind); -SPL_METHOD(Array, current); -SPL_METHOD(Array, key); -SPL_METHOD(Array, next); -SPL_METHOD(Array, valid); -SPL_METHOD(Array, offsetExists); -SPL_METHOD(Array, offsetGet); -SPL_METHOD(Array, offsetSet); -SPL_METHOD(Array, offsetUnset); -SPL_METHOD(Array, append); -SPL_METHOD(Array, getArrayCopy); -SPL_METHOD(Array, exchangeArray); -SPL_METHOD(Array, seek); -SPL_METHOD(Array, count); -SPL_METHOD(Array, getFlags); -SPL_METHOD(Array, setFlags); - -static -ZEND_BEGIN_ARG_INFO(arginfo_array___construct, 0) - ZEND_ARG_INFO(0, array) -ZEND_END_ARG_INFO(); - -static -ZEND_BEGIN_ARG_INFO_EX(arginfo_array_offsetGet, 0, 0, 1) - ZEND_ARG_INFO(0, index) -ZEND_END_ARG_INFO(); - -static -ZEND_BEGIN_ARG_INFO_EX(arginfo_array_offsetSet, 0, 0, 2) - ZEND_ARG_INFO(0, index) - ZEND_ARG_INFO(0, newval) -ZEND_END_ARG_INFO(); - -static -ZEND_BEGIN_ARG_INFO(arginfo_array_append, 0) - ZEND_ARG_INFO(0, value) -ZEND_END_ARG_INFO(); - -static -ZEND_BEGIN_ARG_INFO(arginfo_array_seek, 0) - ZEND_ARG_INFO(0, position) -ZEND_END_ARG_INFO(); - -static -ZEND_BEGIN_ARG_INFO(arginfo_array_exchangeArray, 0) - ZEND_ARG_INFO(0, array) -ZEND_END_ARG_INFO(); - -static -ZEND_BEGIN_ARG_INFO(arginfo_array_setFlags, 0) - ZEND_ARG_INFO(0, flags) -ZEND_END_ARG_INFO(); - -static zend_function_entry spl_funcs_ArrayObject[] = { - SPL_ME(Array, __construct, arginfo_array___construct, ZEND_ACC_PUBLIC) - SPL_ME(Array, offsetExists, arginfo_array_offsetGet, ZEND_ACC_PUBLIC) - SPL_ME(Array, offsetGet, arginfo_array_offsetGet, ZEND_ACC_PUBLIC) - SPL_ME(Array, offsetSet, arginfo_array_offsetSet, ZEND_ACC_PUBLIC) - SPL_ME(Array, offsetUnset, arginfo_array_offsetGet, ZEND_ACC_PUBLIC) - SPL_ME(Array, append, arginfo_array_append, ZEND_ACC_PUBLIC) - SPL_ME(Array, getArrayCopy, NULL, ZEND_ACC_PUBLIC) - SPL_ME(Array, count, NULL, ZEND_ACC_PUBLIC) - SPL_ME(Array, getFlags, NULL, ZEND_ACC_PUBLIC) - SPL_ME(Array, setFlags, arginfo_array_setFlags, ZEND_ACC_PUBLIC) - /* ArrayObject specific */ - SPL_ME(Array, getIterator, NULL, ZEND_ACC_PUBLIC) - SPL_ME(Array, exchangeArray, arginfo_array_exchangeArray, ZEND_ACC_PUBLIC) - {NULL, NULL, NULL} -}; - -static zend_function_entry spl_funcs_ArrayIterator[] = { - SPL_ME(Array, __construct, arginfo_array___construct, ZEND_ACC_PUBLIC) - SPL_ME(Array, offsetExists, arginfo_array_offsetGet, ZEND_ACC_PUBLIC) - SPL_ME(Array, offsetGet, arginfo_array_offsetGet, ZEND_ACC_PUBLIC) - SPL_ME(Array, offsetSet, arginfo_array_offsetSet, ZEND_ACC_PUBLIC) - SPL_ME(Array, offsetUnset, arginfo_array_offsetGet, ZEND_ACC_PUBLIC) - SPL_ME(Array, append, arginfo_array_append, ZEND_ACC_PUBLIC) - SPL_ME(Array, getArrayCopy, NULL, ZEND_ACC_PUBLIC) - SPL_ME(Array, count, NULL, ZEND_ACC_PUBLIC) - SPL_ME(Array, getFlags, NULL, ZEND_ACC_PUBLIC) - SPL_ME(Array, setFlags, arginfo_array_setFlags, ZEND_ACC_PUBLIC) - /* ArrayIterator specific */ - SPL_ME(Array, rewind, NULL, ZEND_ACC_PUBLIC) - SPL_ME(Array, current, NULL, ZEND_ACC_PUBLIC) - SPL_ME(Array, key, NULL, ZEND_ACC_PUBLIC) - SPL_ME(Array, next, NULL, ZEND_ACC_PUBLIC) - SPL_ME(Array, valid, NULL, ZEND_ACC_PUBLIC) - SPL_ME(Array, seek, arginfo_array_seek, ZEND_ACC_PUBLIC) - {NULL, NULL, NULL} -}; - -static zend_function_entry spl_funcs_Countable[] = { - SPL_ABSTRACT_ME(Countable, count, NULL) - {NULL, NULL, NULL} -}; - zend_object_handlers spl_handler_ArrayObject; PHPAPI zend_class_entry *spl_ce_ArrayObject; zend_object_handlers spl_handler_ArrayIterator; PHPAPI zend_class_entry *spl_ce_ArrayIterator; +PHPAPI zend_class_entry *spl_ce_RecursiveArrayIterator; PHPAPI zend_class_entry *spl_ce_Countable; -#define SPL_ARRAY_STD_PROP_LIST 0x00000001 -#define SPL_ARRAY_ARRAY_AS_PROPS 0x00000002 -#define SPL_ARRAY_IS_REF 0x01000000 -#define SPL_ARRAY_IS_SELF 0x02000000 -#define SPL_ARRAY_USE_OTHER 0x04000000 -#define SPL_ARRAY_INT_MASK 0xFF000000 -#define SPL_ARRAY_CLONE_MASK 0x03000003 +#define SPL_ARRAY_STD_PROP_LIST 0x00000001 +#define SPL_ARRAY_ARRAY_AS_PROPS 0x00000002 +#define SPL_ARRAY_IS_REF 0x01000000 +#define SPL_ARRAY_IS_SELF 0x02000000 +#define SPL_ARRAY_USE_OTHER 0x04000000 +#define SPL_ARRAY_INT_MASK 0xFF000000 +#define SPL_ARRAY_CLONE_MASK 0x03000007 typedef struct _spl_array_object { zend_object std; @@ -160,6 +63,7 @@ typedef struct _spl_array_object { zend_function * fptr_offset_set; zend_function * fptr_offset_has; zend_function * fptr_offset_del; + zend_class_entry* ce_get_iterator; } spl_array_object; static inline HashTable *spl_array_get_hash_table(spl_array_object* intern, int check_std_props TSRMLS_DC) { @@ -275,6 +179,7 @@ static zend_object_value spl_array_object_new_ex(zend_class_entry *class_type, s intern->fptr_offset_del = NULL; } } + intern->ce_get_iterator = spl_ce_ArrayIterator; zend_hash_internal_pointer_reset_ex(spl_array_get_hash_table(intern, 0 TSRMLS_CC), &intern->pos); return retval; } @@ -551,7 +456,7 @@ SPL_METHOD(Array, offsetGet) Sets the value at the specified $index to $newval. */ SPL_METHOD(Array, offsetSet) { - zval *index, *value = NULL; + zval *index, *value; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &index, &value) == FAILURE) { return; } @@ -865,7 +770,7 @@ zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object } /* }}} */ -/* {{{ proto void ArrayObject::__construct(array|object ar = array()) +/* {{{ proto void ArrayObject::__construct(array|object ar = array() [, int flags = 0 [, string iterator_class = "ArrayIterator"]]) proto void ArrayIterator::__construct(array|object ar = array() [, int flags = 0]) Cronstructs a new array iterator from a path. */ SPL_METHOD(Array, __construct) @@ -874,6 +779,9 @@ SPL_METHOD(Array, __construct) spl_array_object *intern; zval *array; long ar_flags = 0; + char *class_name; + int class_name_len; + zend_class_entry ** pce_get_iterator; if (ZEND_NUM_ARGS() == 0) { return; /* nothing to do */ @@ -882,11 +790,20 @@ SPL_METHOD(Array, __construct) intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &array, &ar_flags) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|ls", &array, &ar_flags, &class_name, &class_name_len) == FAILURE) { php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC); return; } + if (ZEND_NUM_ARGS() > 2) { + if (zend_lookup_class(class_name, class_name_len, &pce_get_iterator TSRMLS_CC) == FAILURE) { + zend_throw_exception(U_CLASS_ENTRY(spl_ce_InvalidArgumentException), "A class that implements Iterator must be specified", 0 TSRMLS_CC); + php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC); + return; + } + intern->ce_get_iterator = *pce_get_iterator; + } + ar_flags &= ~SPL_ARRAY_INT_MASK; if (Z_TYPE_P(array) == IS_OBJECT && (Z_OBJ_HT_P(array) == &spl_handler_ArrayObject || Z_OBJ_HT_P(array) == &spl_handler_ArrayIterator)) { @@ -914,13 +831,48 @@ SPL_METHOD(Array, __construct) } intern->ar_flags |= ar_flags; ZVAL_ADDREF(intern->array); - + spl_array_rewind(intern TSRMLS_CC); php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC); } /* }}} */ +/* {{{ proto void ArrayObject::setIteratorClass(string iterator_class) + Set the class used in getIterator. */ +SPL_METHOD(Array, setIteratorClass) +{ + zval *object = getThis(); + spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + char *class_name; + int class_name_len; + zend_class_entry ** pce_get_iterator; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &class_name, &class_name_len) == FAILURE) { + php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC); + return; + } + + if (zend_lookup_class(class_name, class_name_len, &pce_get_iterator TSRMLS_CC) == FAILURE) { + zend_throw_exception(U_CLASS_ENTRY(spl_ce_InvalidArgumentException), "A class that implements Iterator must be specified", 0 TSRMLS_CC); + php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC); + return; + } + intern->ce_get_iterator = *pce_get_iterator; +} +/* }}} */ + +/* {{{ proto string ArrayObject::getIteratorClass() + Get the class used in getIterator. */ +SPL_METHOD(Array, getIteratorClass) +{ + zval *object = getThis(); + spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + + RETURN_STRING(intern->ce_get_iterator->name, 1); +} +/* }}} */ + /* {{{ proto int ArrayObject::getFlags() Get flags */ SPL_METHOD(Array, getFlags) @@ -1004,7 +956,7 @@ SPL_METHOD(Array, getIterator) } return_value->type = IS_OBJECT; - return_value->value.obj = spl_array_object_new_ex(U_CLASS_ENTRY(spl_ce_ArrayIterator), &iterator, object TSRMLS_CC); + return_value->value.obj = spl_array_object_new_ex(intern->ce_get_iterator, &iterator, object TSRMLS_CC); return_value->refcount = 1; return_value->is_ref = 1; } @@ -1203,6 +1155,150 @@ SPL_METHOD(Array, valid) } /* }}} */ +/* {{{ proto bool RecursiveArrayIterator::hasChildren() + Check whether current element has children (e.g. is an array) */ +SPL_METHOD(Array, hasChildren) +{ + zval *object = getThis(), **entry; + spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC); + + if (!aht) { + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array"); + RETURN_FALSE; + } + + if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(intern TSRMLS_CC) == FAILURE) { + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid"); + RETURN_FALSE; + } + + if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) { + RETURN_FALSE; + } + + RETURN_BOOL(Z_TYPE_PP(entry) == IS_ARRAY || Z_TYPE_PP(entry) == IS_OBJECT); +} +/* }}} */ + +/* {{{ proto object RecursiveArrayIterator::getChildren() + Create a sub iterator for the current element (same class as $this) */ +SPL_METHOD(Array, getChildren) +{ + zval *object = getThis(), **entry; + spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC); + + if (!aht) { + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array"); + return; + } + + if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(intern TSRMLS_CC) == FAILURE) { + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid"); + return; + } + + if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) { + return; + } + + spl_instantiate_arg_ex1(Z_OBJCE_P(getThis()), &return_value, 0, *entry TSRMLS_CC); +} +/* }}} */ + +static +ZEND_BEGIN_ARG_INFO(arginfo_array___construct, 0) + ZEND_ARG_INFO(0, array) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_array_offsetGet, 0, 0, 1) + ZEND_ARG_INFO(0, index) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_array_offsetSet, 0, 0, 2) + ZEND_ARG_INFO(0, index) + ZEND_ARG_INFO(0, newval) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO(arginfo_array_append, 0) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO(arginfo_array_seek, 0) + ZEND_ARG_INFO(0, position) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO(arginfo_array_exchangeArray, 0) + ZEND_ARG_INFO(0, array) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO(arginfo_array_setFlags, 0) + ZEND_ARG_INFO(0, flags) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO(arginfo_array_setIteratorClass, 0) + ZEND_ARG_INFO(0, iteratorClass) +ZEND_END_ARG_INFO(); + +static zend_function_entry spl_funcs_ArrayObject[] = { + SPL_ME(Array, __construct, arginfo_array___construct, ZEND_ACC_PUBLIC) + SPL_ME(Array, offsetExists, arginfo_array_offsetGet, ZEND_ACC_PUBLIC) + SPL_ME(Array, offsetGet, arginfo_array_offsetGet, ZEND_ACC_PUBLIC) + SPL_ME(Array, offsetSet, arginfo_array_offsetSet, ZEND_ACC_PUBLIC) + SPL_ME(Array, offsetUnset, arginfo_array_offsetGet, ZEND_ACC_PUBLIC) + SPL_ME(Array, append, arginfo_array_append, ZEND_ACC_PUBLIC) + SPL_ME(Array, getArrayCopy, NULL, ZEND_ACC_PUBLIC) + SPL_ME(Array, count, NULL, ZEND_ACC_PUBLIC) + SPL_ME(Array, getFlags, NULL, ZEND_ACC_PUBLIC) + SPL_ME(Array, setFlags, arginfo_array_setFlags, ZEND_ACC_PUBLIC) + /* ArrayObject specific */ + SPL_ME(Array, getIterator, NULL, ZEND_ACC_PUBLIC) + SPL_ME(Array, exchangeArray, arginfo_array_exchangeArray, ZEND_ACC_PUBLIC) + SPL_ME(Array, setIteratorClass, arginfo_array_setIteratorClass, ZEND_ACC_PUBLIC) + SPL_ME(Array, getIteratorClass, NULL, ZEND_ACC_PUBLIC) + {NULL, NULL, NULL} +}; + +static zend_function_entry spl_funcs_ArrayIterator[] = { + SPL_ME(Array, __construct, arginfo_array___construct, ZEND_ACC_PUBLIC) + SPL_ME(Array, offsetExists, arginfo_array_offsetGet, ZEND_ACC_PUBLIC) + SPL_ME(Array, offsetGet, arginfo_array_offsetGet, ZEND_ACC_PUBLIC) + SPL_ME(Array, offsetSet, arginfo_array_offsetSet, ZEND_ACC_PUBLIC) + SPL_ME(Array, offsetUnset, arginfo_array_offsetGet, ZEND_ACC_PUBLIC) + SPL_ME(Array, append, arginfo_array_append, ZEND_ACC_PUBLIC) + SPL_ME(Array, getArrayCopy, NULL, ZEND_ACC_PUBLIC) + SPL_ME(Array, count, NULL, ZEND_ACC_PUBLIC) + SPL_ME(Array, getFlags, NULL, ZEND_ACC_PUBLIC) + SPL_ME(Array, setFlags, arginfo_array_setFlags, ZEND_ACC_PUBLIC) + /* ArrayIterator specific */ + SPL_ME(Array, rewind, NULL, ZEND_ACC_PUBLIC) + SPL_ME(Array, current, NULL, ZEND_ACC_PUBLIC) + SPL_ME(Array, key, NULL, ZEND_ACC_PUBLIC) + SPL_ME(Array, next, NULL, ZEND_ACC_PUBLIC) + SPL_ME(Array, valid, NULL, ZEND_ACC_PUBLIC) + SPL_ME(Array, seek, arginfo_array_seek, ZEND_ACC_PUBLIC) + {NULL, NULL, NULL} +}; + +static zend_function_entry spl_funcs_RecursiveArrayIterator[] = { + SPL_ME(Array, hasChildren, NULL, ZEND_ACC_PUBLIC) + SPL_ME(Array, getChildren, NULL, ZEND_ACC_PUBLIC) + {NULL, NULL, NULL} +}; + +static zend_function_entry spl_funcs_Countable[] = { + SPL_ABSTRACT_ME(Countable, count, NULL) + {NULL, NULL, NULL} +}; + /* {{{ PHP_MINIT_FUNCTION(spl_array) */ PHP_MINIT_FUNCTION(spl_array) { @@ -1230,6 +1326,9 @@ PHP_MINIT_FUNCTION(spl_array) REGISTER_SPL_IMPLEMENTS(ArrayIterator, SeekableIterator); memcpy(&spl_handler_ArrayIterator, &spl_handler_ArrayObject, sizeof(zend_object_handlers)); spl_ce_ArrayIterator->get_iterator = spl_array_get_iterator; + + REGISTER_SPL_SUB_CLASS_EX(RecursiveArrayIterator, ArrayIterator, spl_array_object_new, spl_funcs_RecursiveArrayIterator); + REGISTER_SPL_IMPLEMENTS(RecursiveArrayIterator, RecursiveIterator); REGISTER_SPL_INTERFACE(Countable); diff --git a/ext/spl/spl_array.h b/ext/spl/spl_array.h index 4ee39cb81b..34dedc78dd 100755 --- a/ext/spl/spl_array.h +++ b/ext/spl/spl_array.h @@ -26,6 +26,7 @@ extern PHPAPI zend_class_entry *spl_ce_ArrayObject; extern PHPAPI zend_class_entry *spl_ce_ArrayIterator; +extern PHPAPI zend_class_entry *spl_ce_RecursiveArrayIterator; extern PHPAPI zend_class_entry *spl_ce_Countable; PHP_MINIT_FUNCTION(spl_array); diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c index 0ad559089a..52c1dcbd49 100755 --- a/ext/spl/spl_iterators.c +++ b/ext/spl/spl_iterators.c @@ -89,6 +89,9 @@ typedef struct _spl_recursive_it_object { int level; RecursiveIteratorMode mode; int flags; + zend_bool in_iteration; + zend_function *beginIteration; + zend_function *endIteration; zend_function *callHasChildren; zend_function *callGetChildren; zend_function *beginChildren; @@ -123,7 +126,7 @@ static void spl_recursive_it_dtor(zend_object_iterator *_iter TSRMLS_DC) efree(iter); } -static int spl_recursive_it_valid_ex(spl_recursive_it_object *object TSRMLS_DC) +static int spl_recursive_it_valid_ex(spl_recursive_it_object *object, zval *zthis TSRMLS_DC) { zend_object_iterator *sub_iter; int level = object->level; @@ -135,6 +138,10 @@ static int spl_recursive_it_valid_ex(spl_recursive_it_object *object TSRMLS_DC) } level--; } + if (object->endIteration && object->in_iteration) { + zend_call_method_with_0_params(&zthis, object->ce, &object->endIteration, "endIteration", NULL); + } + object->in_iteration = 0; return FAILURE; } @@ -142,7 +149,7 @@ static int spl_recursive_it_valid(zend_object_iterator *iter TSRMLS_DC) { spl_recursive_it_object *object = (spl_recursive_it_object*)iter->data; - return spl_recursive_it_valid_ex(object TSRMLS_CC); + return spl_recursive_it_valid_ex(object, ((spl_recursive_it_iterator*)iter)->zobject TSRMLS_CC); } static void spl_recursive_it_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) @@ -306,6 +313,10 @@ static void spl_recursive_it_rewind_ex(spl_recursive_it_object *object, zval *zt if (sub_iter->funcs->rewind) { sub_iter->funcs->rewind(sub_iter TSRMLS_CC); } + if (object->beginIteration && !object->in_iteration) { + zend_call_method_with_0_params(&zthis, object->ce, &object->beginIteration, "beginIteration", NULL); + } + object->in_iteration = 1; spl_recursive_it_move_forward_ex(object, zthis TSRMLS_CC); } @@ -371,7 +382,16 @@ SPL_METHOD(RecursiveIteratorIterator, __construct) intern->level = 0; intern->mode = mode; intern->flags = flags; + intern->in_iteration = 0; intern->ce = Z_OBJCE_P(object); + zend_hash_find(&intern->ce->function_table, "beginiteration", sizeof("beginiteration"), (void **) &intern->beginIteration); + if (intern->beginIteration->common.scope == U_CLASS_ENTRY(spl_ce_RecursiveIteratorIterator)) { + intern->beginIteration = NULL; + } + zend_hash_find(&intern->ce->function_table, "enditeration", sizeof("enditeration"), (void **) &intern->endIteration); + if (intern->endIteration->common.scope == U_CLASS_ENTRY(spl_ce_RecursiveIteratorIterator)) { + intern->endIteration = NULL; + } zend_hash_find(&intern->ce->function_table, "callhaschildren", sizeof("callHasChildren"), (void **) &intern->callHasChildren); if (intern->callHasChildren->common.scope == U_CLASS_ENTRY(spl_ce_RecursiveIteratorIterator)) { intern->callHasChildren = NULL; @@ -417,7 +437,7 @@ SPL_METHOD(RecursiveIteratorIterator, valid) { spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); - RETURN_BOOL(spl_recursive_it_valid_ex(object TSRMLS_CC) == SUCCESS); + RETURN_BOOL(spl_recursive_it_valid_ex(object, getThis() TSRMLS_CC) == SUCCESS); } /* }}} */ /* {{{ proto mixed RecursiveIteratorIterator::key() @@ -497,6 +517,20 @@ SPL_METHOD(RecursiveIteratorIterator, getInnerIterator) RETURN_ZVAL(object->iterators[level].zobject, 1, 0); } /* }}} */ +/* {{{ proto RecursiveIterator RecursiveIteratorIterator::beginIteration() + Called when iteration begins (after first rewind() call) */ +SPL_METHOD(RecursiveIteratorIterator, beginIteration) +{ + /* nothing to do */ +} /* }}} */ + +/* {{{ proto RecursiveIterator RecursiveIteratorIterator::endIteration() + Called when iteration ends (when valid() first returns false */ +SPL_METHOD(RecursiveIteratorIterator, endIteration) +{ + /* nothing to do */ +} /* }}} */ + /* {{{ proto bool RecursiveIteratorIterator::callHasChildren() Called for each element to test whether it has children */ SPL_METHOD(RecursiveIteratorIterator, callHasChildren) @@ -637,6 +671,8 @@ static zend_function_entry spl_funcs_RecursiveIteratorIterator[] = { SPL_ME(RecursiveIteratorIterator, getDepth, NULL, ZEND_ACC_PUBLIC) SPL_ME(RecursiveIteratorIterator, getSubIterator, arginfo_recursive_it_getSubIterator, ZEND_ACC_PUBLIC) SPL_ME(RecursiveIteratorIterator, getInnerIterator, NULL, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveIteratorIterator, beginIteration, NULL, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveIteratorIterator, endIteration, NULL, ZEND_ACC_PUBLIC) SPL_ME(RecursiveIteratorIterator, callHasChildren, NULL, ZEND_ACC_PUBLIC) SPL_ME(RecursiveIteratorIterator, callGetChildren, NULL, ZEND_ACC_PUBLIC) SPL_ME(RecursiveIteratorIterator, beginChildren, NULL, ZEND_ACC_PUBLIC) @@ -765,6 +801,8 @@ static INLINE spl_dual_it_object* spl_dual_it_construct(INTERNAL_FUNCTION_PARAME return NULL; } intern->u.caching.flags |= flags & CIT_PUBLIC; + MAKE_STD_ZVAL(intern->u.caching.zcache); + array_init(intern->u.caching.zcache); break; } case DIT_IteratorIterator: { @@ -1097,7 +1135,7 @@ SPL_METHOD(RecursiveFilterIterator, getChildren) 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(U_CLASS_ENTRY(spl_ce_RecursiveFilterIterator), &return_value, 0, retval TSRMLS_CC); + spl_instantiate_arg_ex1(Z_OBJCE_P(getThis()), &return_value, 0, retval TSRMLS_CC); zval_ptr_dtor(&retval); } /* }}} */ @@ -1131,7 +1169,7 @@ SPL_METHOD(ParentIterator, getChildren) 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(U_CLASS_ENTRY(spl_ce_ParentIterator), &return_value, 0, retval TSRMLS_CC); + spl_instantiate_arg_ex1(Z_OBJCE_P(getThis()), &return_value, 0, retval TSRMLS_CC); zval_ptr_dtor(&retval); } /* }}} */ @@ -1155,6 +1193,13 @@ static INLINE void spl_dual_it_free_storage(void *_object TSRMLS_DC) zval_ptr_dtor(&object->u.append.zarrayit); } + if (object->dit_type == DIT_CachingIterator || object->dit_type == DIT_CachingRecursiveIterator) { + if (object->u.caching.zcache) { + zval_ptr_dtor(&object->u.caching.zcache); + object->u.caching.zcache = NULL; + } + } + zend_hash_destroy(object->std.properties); FREE_HASHTABLE(object->std.properties); @@ -1388,6 +1433,22 @@ static INLINE void spl_caching_it_next(spl_dual_it_object *intern TSRMLS_DC) { if (spl_dual_it_fetch(intern, 1 TSRMLS_CC) == SUCCESS) { intern->u.caching.flags |= CIT_VALID; + /* Full cache ? */ + if (intern->u.caching.flags & CIT_FULL_CACHE) { + zval *zcacheval; + + MAKE_STD_ZVAL(zcacheval); + ZVAL_ZVAL(zcacheval, intern->current.data, 1, 0); + switch(intern->current.key_type) { + case HASH_KEY_IS_STRING: + zend_u_symtable_update(HASH_OF(intern->u.caching.zcache), IS_STRING, intern->current.str_key, intern->current.str_key_len, &zcacheval, sizeof(void*), NULL); + break; + case HASH_KEY_IS_LONG: + add_index_zval(intern->u.caching.zcache, intern->current.int_key, zcacheval); + break; + } + } + /* Recursion ? */ if (intern->dit_type == DIT_CachingRecursiveIterator) { zval *retval, *zchildren, zflags; zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "haschildren", &retval); @@ -1459,6 +1520,7 @@ static INLINE void spl_caching_it_next(spl_dual_it_object *intern TSRMLS_DC) static INLINE void spl_caching_it_rewind(spl_dual_it_object *intern TSRMLS_DC) { spl_dual_it_rewind(intern TSRMLS_CC); + zend_hash_clean(HASH_OF(intern->u.caching.zcache)); spl_caching_it_next(intern TSRMLS_CC); } @@ -1534,12 +1596,165 @@ SPL_METHOD(CachingIterator, __toString) } } /* }}} */ +/* {{{ proto void CachingIterator::offsetSet(mixed index, mixed newval) + Set given index in cache */ +SPL_METHOD(CachingIterator, offsetSet) +{ + spl_dual_it_object *intern; + void *arKey; + uint nKeyLength; + zend_uchar type; + zval *value; + + intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (!(intern->u.caching.flags & CIT_FULL_CACHE)) { + zend_throw_exception_ex(U_CLASS_ENTRY(spl_ce_BadMethodCallException), 0 TSRMLS_CC, "%v does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name); + } + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Tz", &arKey, &nKeyLength, &type, &value) == FAILURE) { + return; + } + + value->refcount++; + zend_u_symtable_update(HASH_OF(intern->u.caching.zcache), type, arKey, nKeyLength+1, &value, sizeof(value), NULL); +} +/* }}} */ + +/* {{{ proto string CachingIterator::offsetGet(mixed index) + Return the internal cache if used */ +SPL_METHOD(CachingIterator, offsetGet) +{ + spl_dual_it_object *intern; + void *arKey; + uint nKeyLength; + zend_uchar type; + zval **value; + + intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (!(intern->u.caching.flags & CIT_FULL_CACHE)) { + zend_throw_exception_ex(U_CLASS_ENTRY(spl_ce_BadMethodCallException), 0 TSRMLS_CC, "%v does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name); + } + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "T", &arKey, &nKeyLength, &type) == FAILURE) { + return; + } + + if (zend_u_symtable_find(HASH_OF(intern->u.caching.zcache), type, arKey, nKeyLength+1, (void**)&value) == FAILURE) { + zend_error(E_NOTICE, "Undefined index: %R", type, arKey); + return; + } + + RETURN_ZVAL(*value, 1, 0); +} +/* }}} */ + +/* {{{ proto void CachingIterator::offsetUnset(mixed index) + Unset given index in cache */ +SPL_METHOD(CachingIterator, offsetUnset) +{ + spl_dual_it_object *intern; + void *arKey; + uint nKeyLength; + zend_uchar type; + + intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (!(intern->u.caching.flags & CIT_FULL_CACHE)) { + zend_throw_exception_ex(U_CLASS_ENTRY(spl_ce_BadMethodCallException), 0 TSRMLS_CC, "%v does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name); + } + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "T", &arKey, &nKeyLength, &type) == FAILURE) { + return; + } + + zend_u_symtable_del(HASH_OF(intern->u.caching.zcache), type, arKey, nKeyLength+1); +} +/* }}} */ + +/* {{{ proto bool CachingIterator::offsetExists(mixed index) + Return whether the requested index exists */ +SPL_METHOD(CachingIterator, offsetExists) +{ + spl_dual_it_object *intern; + void *arKey; + uint nKeyLength; + zend_uchar type; + + intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (!(intern->u.caching.flags & CIT_FULL_CACHE)) { + zend_throw_exception_ex(U_CLASS_ENTRY(spl_ce_BadMethodCallException), 0 TSRMLS_CC, "%v does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name); + } + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "T", &arKey, &nKeyLength, &type) == FAILURE) { + return; + } + + RETURN_BOOL(zend_u_symtable_exists(HASH_OF(intern->u.caching.zcache), type, arKey, nKeyLength+1)); +} +/* }}} */ + +/* {{{ proto int CachingIterator::getFlags() + Return the internal flags */ +SPL_METHOD(CachingIterator, getFlags) +{ + spl_dual_it_object *intern; + + intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + RETURN_LONG(intern->u.caching.flags); +} +/* }}} */ + +/* {{{ proto void CachingIterator::setFlags() + Set the internal flags */ +SPL_METHOD(CachingIterator, setFlags) +{ + spl_dual_it_object *intern; + long flags; + + intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", flags) == FAILURE) { + return; + } + + if ((intern->u.caching.flags & CIT_CALL_TOSTRING) != 0 && (flags & ~CIT_CALL_TOSTRING) == 0) { + zend_throw_exception(U_CLASS_ENTRY(spl_ce_InvalidArgumentException), "Unsetting flag CALL_TO_STRING is not possible", 0 TSRMLS_CC); + return; + } + if ((flags && CIT_FULL_CACHE) != 0 && (intern->u.caching.flags & CIT_FULL_CACHE) == 0) { + /* clear on (re)enable */ + zend_hash_clean(HASH_OF(intern->u.caching.zcache)); + } + intern->u.caching.flags = (intern->u.caching.flags & ~CIT_PUBLIC) | (flags & CIT_PUBLIC); +} +/* }}} */ + static ZEND_BEGIN_ARG_INFO(arginfo_caching_it___construct, 0) ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0) ZEND_ARG_INFO(0, flags) ZEND_END_ARG_INFO(); +static +ZEND_BEGIN_ARG_INFO(arginfo_caching_it_setFlags, 0) + ZEND_ARG_INFO(0, flags) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_caching_it_offsetGet, 0, 0, 1) + ZEND_ARG_INFO(0, index) +ZEND_END_ARG_INFO(); + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_caching_it_offsetSet, 0, 0, 2) + ZEND_ARG_INFO(0, index) + ZEND_ARG_INFO(0, newval) +ZEND_END_ARG_INFO(); + static zend_function_entry spl_funcs_CachingIterator[] = { SPL_ME(CachingIterator, __construct, arginfo_caching_it___construct, ZEND_ACC_PUBLIC) SPL_ME(CachingIterator, rewind, NULL, ZEND_ACC_PUBLIC) @@ -1550,6 +1765,12 @@ static zend_function_entry spl_funcs_CachingIterator[] = { SPL_ME(CachingIterator, hasNext, NULL, ZEND_ACC_PUBLIC) SPL_ME(CachingIterator, __toString, NULL, ZEND_ACC_PUBLIC) SPL_ME(dual_it, getInnerIterator, NULL, ZEND_ACC_PUBLIC) + SPL_ME(CachingIterator, getFlags, NULL, ZEND_ACC_PUBLIC) + SPL_ME(CachingIterator, setFlags, arginfo_caching_it_setFlags, ZEND_ACC_PUBLIC) + SPL_ME(CachingIterator, offsetGet, arginfo_caching_it_offsetGet, ZEND_ACC_PUBLIC) + SPL_ME(CachingIterator, offsetSet, arginfo_caching_it_offsetSet, ZEND_ACC_PUBLIC) + SPL_ME(CachingIterator, offsetUnset, arginfo_caching_it_offsetGet, ZEND_ACC_PUBLIC) + SPL_ME(CachingIterator, offsetExists, arginfo_caching_it_offsetGet, ZEND_ACC_PUBLIC) {NULL, NULL, NULL} }; @@ -1842,7 +2063,7 @@ SPL_METHOD(AppendIterator, append) intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &it, U_CLASS_ENTRY(zend_ce_iterator)) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &it, U_CLASS_ENTRY(zend_ce_iterator)) == FAILURE) { return; } spl_array_iterator_append(intern->u.append.zarrayit, it TSRMLS_CC); @@ -2032,9 +2253,11 @@ PHP_MINIT_FUNCTION(spl_iterators) REGISTER_SPL_STD_CLASS_EX(CachingIterator, spl_dual_it_new, spl_funcs_CachingIterator); REGISTER_SPL_ITERATOR(CachingIterator); + REGISTER_SPL_IMPLEMENTS(CachingIterator, ArrayAccess); 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_CLASS_CONST_LONG(CachingIterator, "FULL_CACHE", CIT_FULL_CACHE); 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 3e0d0cba11..582db5e946 100755 --- a/ext/spl/spl_iterators.h +++ b/ext/spl/spl_iterators.h @@ -64,12 +64,13 @@ typedef enum { enum { /* public */ - CIT_CALL_TOSTRING = 1, - CIT_CATCH_GET_CHILD = 2, - CIT_PUBLIC = CIT_CALL_TOSTRING|CIT_CATCH_GET_CHILD, + CIT_CALL_TOSTRING = 0x00000001, + CIT_CATCH_GET_CHILD = 0x00000002, + CIT_FULL_CACHE = 0x00000004, + CIT_PUBLIC = 0x00FFFFFF, /* private */ - CIT_VALID = 4, - CIT_HAS_CHILDREN = 8 + CIT_VALID = 0x01000000, + CIT_HAS_CHILDREN = 0x02000000, }; typedef struct _spl_dual_it_object { @@ -95,9 +96,10 @@ typedef struct _spl_dual_it_object { long count; } limit; struct { - int flags; /* CIT_VALID, CIT_CALL_TOSTRING, CIT_CATCH_GET_CHILD */ + int flags; /* CIT_VALID, CIT_CALL_TOSTRING, CIT_CATCH_GET_CHILD, ... */ zval *zstr; zval *zchildren; + zval *zcache; } caching; struct { zval *zarrayit; diff --git a/ext/spl/tests/array_009.phpt b/ext/spl/tests/array_009.phpt index fce2b42df2..0431cca77e 100755 --- a/ext/spl/tests/array_009.phpt +++ b/ext/spl/tests/array_009.phpt @@ -5,22 +5,9 @@ SPL: ArrayIterator implementing RecursiveIterator --FILE-- current()); - } - - function getChildren() - { - return new RecursiceArrayIterator($this->current()); - } -} - $array = array(1, 2 => array(21, 22 => array(221, 222), 23 => array(231)), 3); -$dir = new RecursiveIteratorIterator(new RecursiceArrayIterator($array), RecursiveIteratorIterator::LEAVES_ONLY); +$dir = new RecursiveIteratorIterator(new RecursiveArrayIterator($array), RecursiveIteratorIterator::LEAVES_ONLY); foreach ($dir as $file) { print "$file\n"; diff --git a/ext/spl/tests/array_009a.phpt b/ext/spl/tests/array_009a.phpt new file mode 100755 index 0000000000..aebac08ba6 --- /dev/null +++ b/ext/spl/tests/array_009a.phpt @@ -0,0 +1,39 @@ +--TEST-- +SPL: ArrayIterator implementing RecursiveIterator +--SKIPIF-- + +--FILE-- +current()); + } + + function getChildren() + { + return new MyRecursiveArrayIterator($this->current()); + } +} + +$array = array(1, 2 => array(21, 22 => array(221, 222), 23 => array(231)), 3); + +$dir = new RecursiveIteratorIterator(new MyRecursiveArrayIterator($array), RecursiveIteratorIterator::LEAVES_ONLY); + +foreach ($dir as $file) { + print "$file\n"; +} + +?> +===DONE=== + +--EXPECT-- +1 +21 +221 +222 +231 +3 +===DONE=== diff --git a/ext/spl/tests/bug31926.phpt b/ext/spl/tests/bug31926.phpt index 1159051a4a..bcc9ed3d2c 100755 --- a/ext/spl/tests/bug31926.phpt +++ b/ext/spl/tests/bug31926.phpt @@ -5,17 +5,6 @@ Bug #31926 (php in free() error with RecursiveArrayIterator) $array = array(0 => array('world')); -class RecursiveArrayIterator extends ArrayIterator implements -RecursiveIterator { - function hasChildren() { - return (is_array($this->current())); - } - - function getChildren() { - return new self($this->current()); - } -} - $it = new RecursiveIteratorIterator(new RecursiveArrayIterator($array)); foreach($it as $key => $val) { var_dump($key, $val); diff --git a/ext/spl/tests/iterator_014.phpt b/ext/spl/tests/iterator_014.phpt index f6e8ce9d01..119fad05fb 100755 --- a/ext/spl/tests/iterator_014.phpt +++ b/ext/spl/tests/iterator_014.phpt @@ -3,19 +3,8 @@ SPL: RecursiveIteratorIterator and beginChildren/endChildren --FILE-- current()); - } - - function getChildren() - { - echo __METHOD__ . "\n"; - return new RecursiveArrayIterator($this->current()); - } - function valid() { if (!parent::valid()) @@ -28,6 +17,12 @@ class RecursiveArrayIterator extends ArrayIterator implements RecursiveIterator return true; } } + + function getChildren() + { + echo __METHOD__ . "\n"; + return parent::getChildren(); + } } class RecursiveArrayIteratorIterator extends RecursiveIteratorIterator @@ -73,7 +68,7 @@ class RecursiveArrayIteratorIterator extends RecursiveIteratorIterator } } -foreach(new RecursiveArrayIteratorIterator(new RecursiveArrayIterator(array("a", array("ba", array("bba", "bbb"), array(array("bcaa"))), array("ca"), "d"))) as $k=>$v) +foreach(new RecursiveArrayIteratorIterator(new MyRecursiveArrayIterator(array("a", array("ba", array("bba", "bbb"), array(array("bcaa"))), array("ca"), "d"))) as $k=>$v) { echo "$k=>$v\n"; } @@ -87,14 +82,14 @@ RecursiveArrayIteratorIterator::current RecursiveArrayIteratorIterator::key 0=>a RecursiveArrayIteratorIterator::next -RecursiveArrayIterator::getChildren +MyRecursiveArrayIterator::getChildren RecursiveArrayIteratorIterator::beginChildren(1) RecursiveArrayIteratorIterator::valid RecursiveArrayIteratorIterator::current RecursiveArrayIteratorIterator::key 0=>ba RecursiveArrayIteratorIterator::next -RecursiveArrayIterator::getChildren +MyRecursiveArrayIterator::getChildren RecursiveArrayIteratorIterator::beginChildren(2) RecursiveArrayIteratorIterator::valid RecursiveArrayIteratorIterator::current @@ -106,38 +101,38 @@ RecursiveArrayIteratorIterator::current RecursiveArrayIteratorIterator::key 1=>bbb RecursiveArrayIteratorIterator::next -RecursiveArrayIterator::valid = false +MyRecursiveArrayIterator::valid = false RecursiveArrayIteratorIterator::endChildren(2) -RecursiveArrayIterator::getChildren +MyRecursiveArrayIterator::getChildren RecursiveArrayIteratorIterator::beginChildren(2) -RecursiveArrayIterator::getChildren +MyRecursiveArrayIterator::getChildren RecursiveArrayIteratorIterator::beginChildren(3) RecursiveArrayIteratorIterator::valid RecursiveArrayIteratorIterator::current RecursiveArrayIteratorIterator::key 0=>bcaa RecursiveArrayIteratorIterator::next -RecursiveArrayIterator::valid = false +MyRecursiveArrayIterator::valid = false RecursiveArrayIteratorIterator::endChildren(3) -RecursiveArrayIterator::valid = false +MyRecursiveArrayIterator::valid = false RecursiveArrayIteratorIterator::endChildren(2) -RecursiveArrayIterator::valid = false +MyRecursiveArrayIterator::valid = false RecursiveArrayIteratorIterator::endChildren(1) -RecursiveArrayIterator::getChildren +MyRecursiveArrayIterator::getChildren RecursiveArrayIteratorIterator::beginChildren(1) RecursiveArrayIteratorIterator::valid RecursiveArrayIteratorIterator::current RecursiveArrayIteratorIterator::key 0=>ca RecursiveArrayIteratorIterator::next -RecursiveArrayIterator::valid = false +MyRecursiveArrayIterator::valid = false RecursiveArrayIteratorIterator::endChildren(1) RecursiveArrayIteratorIterator::valid RecursiveArrayIteratorIterator::current RecursiveArrayIteratorIterator::key 3=>d RecursiveArrayIteratorIterator::next -RecursiveArrayIterator::valid = false +MyRecursiveArrayIterator::valid = false RecursiveArrayIteratorIterator::valid -RecursiveArrayIterator::valid = false +MyRecursiveArrayIterator::valid = false ===DONE=== diff --git a/ext/spl/tests/iterator_015.phpt b/ext/spl/tests/iterator_015.phpt index 3a18efd80f..aa30f79e1f 100755 --- a/ext/spl/tests/iterator_015.phpt +++ b/ext/spl/tests/iterator_015.phpt @@ -3,19 +3,6 @@ SPL: RecursiveIteratorIterator and beginChildren/endChildren --FILE-- current()); - } - - function getChildren() - { - return new RecursiveArrayIterator($this->current()); - } -} - class RecursiveArrayIteratorIterator extends RecursiveIteratorIterator { function rewind() diff --git a/ext/spl/tests/iterator_016.phpt b/ext/spl/tests/iterator_016.phpt index 6a811edf29..f231c6eb34 100755 --- a/ext/spl/tests/iterator_016.phpt +++ b/ext/spl/tests/iterator_016.phpt @@ -3,19 +3,6 @@ SPL: RecursiveIteratorIterator and beginChildren/endChildren --FILE-- current()); - } - - function getChildren() - { - return new RecursiveArrayIterator($this->current()); - } -} - class Menu extends ArrayObject { function getIterator() diff --git a/ext/spl/tests/iterator_021.phpt b/ext/spl/tests/iterator_021.phpt index 115461d053..4f2395a8e5 100755 --- a/ext/spl/tests/iterator_021.phpt +++ b/ext/spl/tests/iterator_021.phpt @@ -3,19 +3,8 @@ SPL: RecursiveIteratorIterator and hasChildren --FILE-- current()); - } - - function getChildren() - { - echo __METHOD__ . "\n"; - return new RecursiveArrayIterator($this->current()); - } - function valid() { if (!parent::valid()) @@ -28,6 +17,12 @@ class RecursiveArrayIterator extends ArrayIterator implements RecursiveIterator return true; } } + + function getChildren() + { + echo __METHOD__ . "\n"; + return parent::getChildren(); + } } class RecursiveArrayIteratorIterator extends RecursiveIteratorIterator @@ -105,7 +100,7 @@ class RecursiveArrayIteratorIterator extends RecursiveIteratorIterator } } -foreach(new RecursiveArrayIteratorIterator(new RecursiveArrayIterator(array("a", array("ba", array("bba", "bbb"), array(array("bcaa"), array("bcba"))), array("ca"), "d")), 2) as $k=>$v) +foreach(new RecursiveArrayIteratorIterator(new MyRecursiveArrayIterator(array("a", array("ba", array("bba", "bbb"), array(array("bcaa"), array("bcba"))), array("ca"), "d")), 2) as $k=>$v) { if (is_array($v)) $v = join('',$v); echo "$k=>$v\n"; @@ -122,7 +117,7 @@ RecursiveArrayIteratorIterator::key 0=>a RecursiveArrayIteratorIterator::next RecursiveArrayIteratorIterator::callHasChildren(0) = yes/yes -RecursiveArrayIterator::getChildren +MyRecursiveArrayIterator::getChildren RecursiveArrayIteratorIterator::beginChildren(1) RecursiveArrayIteratorIterator::callHasChildren(1) = no/no RecursiveArrayIteratorIterator::valid @@ -131,7 +126,7 @@ RecursiveArrayIteratorIterator::key 0=>ba RecursiveArrayIteratorIterator::next RecursiveArrayIteratorIterator::callHasChildren(1) = yes/yes -RecursiveArrayIterator::getChildren +MyRecursiveArrayIterator::getChildren RecursiveArrayIteratorIterator::beginChildren(2) RecursiveArrayIteratorIterator::callHasChildren(2) = no/no RecursiveArrayIteratorIterator::valid @@ -145,10 +140,10 @@ RecursiveArrayIteratorIterator::current RecursiveArrayIteratorIterator::key 1=>bbb RecursiveArrayIteratorIterator::next -RecursiveArrayIterator::valid = false +MyRecursiveArrayIterator::valid = false RecursiveArrayIteratorIterator::endChildren(2) RecursiveArrayIteratorIterator::callHasChildren(1) = yes/yes -RecursiveArrayIterator::getChildren +MyRecursiveArrayIterator::getChildren RecursiveArrayIteratorIterator::beginChildren(2) RecursiveArrayIteratorIterator::callHasChildren(2) = no/yes RecursiveArrayIteratorIterator::valid @@ -159,19 +154,19 @@ RecursiveArrayIteratorIterator::next RecursiveArrayIteratorIterator::callHasChildren(2) = no/yes RecursiveArrayIteratorIterator::valid RecursiveArrayIteratorIterator::next -RecursiveArrayIterator::valid = false +MyRecursiveArrayIterator::valid = false RecursiveArrayIteratorIterator::endChildren(2) -RecursiveArrayIterator::valid = false +MyRecursiveArrayIterator::valid = false RecursiveArrayIteratorIterator::endChildren(1) RecursiveArrayIteratorIterator::callHasChildren(0) = yes/yes -RecursiveArrayIterator::getChildren +MyRecursiveArrayIterator::getChildren RecursiveArrayIteratorIterator::beginChildren(1) RecursiveArrayIteratorIterator::callHasChildren(1) = no/no RecursiveArrayIteratorIterator::current RecursiveArrayIteratorIterator::key 0=>ca RecursiveArrayIteratorIterator::next -RecursiveArrayIterator::valid = false +MyRecursiveArrayIterator::valid = false RecursiveArrayIteratorIterator::endChildren(1) RecursiveArrayIteratorIterator::callHasChildren(0) = no/no RecursiveArrayIteratorIterator::valid @@ -179,7 +174,7 @@ RecursiveArrayIteratorIterator::current RecursiveArrayIteratorIterator::key 3=>d RecursiveArrayIteratorIterator::next -RecursiveArrayIterator::valid = false +MyRecursiveArrayIterator::valid = false RecursiveArrayIteratorIterator::valid -RecursiveArrayIterator::valid = false +MyRecursiveArrayIterator::valid = false ===DONE=== diff --git a/ext/spl/tests/iterator_022.phpt b/ext/spl/tests/iterator_022.phpt index 12bec48b15..8d055313ac 100755 --- a/ext/spl/tests/iterator_022.phpt +++ b/ext/spl/tests/iterator_022.phpt @@ -3,13 +3,8 @@ SPL: RecursiveIteratorIterator and callHasChildren/callGetChildren --FILE-- current()); - } - function getChildren() { echo __METHOD__ . "\n"; @@ -102,7 +97,7 @@ class RecursiveArrayIteratorIterator extends RecursiveIteratorIterator return NULL; } echo __METHOD__ . "(ok:{$this->over})\n"; - return new RecursiveArrayIterator($this->current()); + return new MyRecursiveArrayIterator($this->current()); } function beginChildren() @@ -118,7 +113,7 @@ class RecursiveArrayIteratorIterator extends RecursiveIteratorIterator try { - foreach(new RecursiveArrayIteratorIterator(new RecursiveArrayIterator(array("a", array("ba", array("bba", "bbb"), array(array("bcaa"), array("bcba"))), array("ca"), "d")), 2) as $k=>$v) + foreach(new RecursiveArrayIteratorIterator(new MyRecursiveArrayIterator(array("a", array("ba", array("bba", "bbb"), array(array("bcaa"), array("bcba"))), array("ca"), "d")), 2) as $k=>$v) { if (is_array($v)) $v = join('',$v); echo "$k=>$v\n"; @@ -166,7 +161,7 @@ RecursiveArrayIteratorIterator::current RecursiveArrayIteratorIterator::key 1=>bbb RecursiveArrayIteratorIterator::next -RecursiveArrayIterator::valid = false +MyRecursiveArrayIterator::valid = false RecursiveArrayIteratorIterator::endChildren(2) RecursiveArrayIteratorIterator::callHasChildren(1) = yes/yes RecursiveArrayIteratorIterator::callGetChildren(ok:0) @@ -181,9 +176,9 @@ RecursiveArrayIteratorIterator::next RecursiveArrayIteratorIterator::callHasChildren(2) = no/yes RecursiveArrayIteratorIterator::valid RecursiveArrayIteratorIterator::next -RecursiveArrayIterator::valid = false +MyRecursiveArrayIterator::valid = false RecursiveArrayIteratorIterator::endChildren(2) -RecursiveArrayIterator::valid = false +MyRecursiveArrayIterator::valid = false RecursiveArrayIteratorIterator::endChildren(1) RecursiveArrayIteratorIterator::callHasChildren(0) = yes/yes RecursiveArrayIteratorIterator::callGetChildren(skip) diff --git a/ext/spl/tests/iterator_023.phpt b/ext/spl/tests/iterator_023.phpt index 8521fa4674..1b6b4685ec 100755 --- a/ext/spl/tests/iterator_023.phpt +++ b/ext/spl/tests/iterator_023.phpt @@ -3,13 +3,8 @@ SPL: RecursiveIteratorIterator and catch getChildren --FILE-- current()); - } - function getChildren() { echo __METHOD__ . "\n"; @@ -102,7 +97,7 @@ class RecursiveArrayIteratorIterator extends RecursiveIteratorIterator throw new Exception("Thrown in callGetChildren()"); } echo __METHOD__ . "(ok:{$this->over})\n"; - return new RecursiveArrayIterator($this->current()); + return new MyRecursiveArrayIterator($this->current()); } function beginChildren() @@ -118,7 +113,7 @@ class RecursiveArrayIteratorIterator extends RecursiveIteratorIterator try { - foreach(new RecursiveArrayIteratorIterator(new RecursiveArrayIterator(array("a", array("ba", array("bba", "bbb"), array(array("bcaa"), array("bcba"))), array("ca"), "d")), 2) as $k=>$v) + foreach(new RecursiveArrayIteratorIterator(new MyRecursiveArrayIterator(array("a", array("ba", array("bba", "bbb"), array(array("bcaa"), array("bcba"))), array("ca"), "d")), 2) as $k=>$v) { if (is_array($v)) $v = join('',$v); echo "$k=>$v\n"; @@ -166,7 +161,7 @@ RecursiveArrayIteratorIterator::current RecursiveArrayIteratorIterator::key 1=>bbb RecursiveArrayIteratorIterator::next -RecursiveArrayIterator::valid = false +MyRecursiveArrayIterator::valid = false RecursiveArrayIteratorIterator::endChildren(2) RecursiveArrayIteratorIterator::callHasChildren(1) = yes/yes RecursiveArrayIteratorIterator::callGetChildren(ok:0) @@ -181,9 +176,9 @@ RecursiveArrayIteratorIterator::next RecursiveArrayIteratorIterator::callHasChildren(2) = no/yes RecursiveArrayIteratorIterator::valid RecursiveArrayIteratorIterator::next -RecursiveArrayIterator::valid = false +MyRecursiveArrayIterator::valid = false RecursiveArrayIteratorIterator::endChildren(2) -RecursiveArrayIterator::valid = false +MyRecursiveArrayIterator::valid = false RecursiveArrayIteratorIterator::endChildren(1) RecursiveArrayIteratorIterator::callHasChildren(0) = yes/yes RecursiveArrayIteratorIterator::callGetChildren(throw) @@ -192,7 +187,7 @@ RecursiveArrayIteratorIterator::current RecursiveArrayIteratorIterator::key 3=>d RecursiveArrayIteratorIterator::next -RecursiveArrayIterator::valid = false +MyRecursiveArrayIterator::valid = false RecursiveArrayIteratorIterator::valid -RecursiveArrayIterator::valid = false +MyRecursiveArrayIterator::valid = false ===DONE=== diff --git a/ext/spl/tests/iterator_024.phpt b/ext/spl/tests/iterator_024.phpt new file mode 100755 index 0000000000..0c7dea15bc --- /dev/null +++ b/ext/spl/tests/iterator_024.phpt @@ -0,0 +1,49 @@ +--TEST-- +SPL: RecursiveIteratorIterator with custom iterator class +--FILE-- +getIteratorClass()); + +try +{ + foreach(new RecursiveIteratorIterator(new ArrayObject($ar)) as $v) echo "$v\n"; +} +catch (InvalidArgumentException $e) +{ + echo $e->getMessage() . "\n"; +} + +echo "===MANUAL===\n"; + +$it->setIteratorClass("RecursiveArrayIterator"); +var_dump($it->getIteratorClass()); +foreach(new RecursiveIteratorIterator($it) as $v) echo "$v\n"; + + +?> +===DONE=== + +--EXPECT-- +1 +2 +31 +32 +331 +4 +string(13) "ArrayIterator" +An instance of RecursiveIterator or IteratorAggregate creating it is required +===MANUAL=== +string(22) "RecursiveArrayIterator" +1 +2 +31 +32 +331 +4 +===DONE=== diff --git a/ext/spl/tests/iterator_025.phpt b/ext/spl/tests/iterator_025.phpt new file mode 100755 index 0000000000..e582b1f39e --- /dev/null +++ b/ext/spl/tests/iterator_025.phpt @@ -0,0 +1,92 @@ +--TEST-- +SPL: RecursiveIteratorIterator and begin/endIteration() +--FILE-- +rewind(); +foreach($it as $v) echo "$v\n"; +var_dump($it->valid()); + +echo "===MANUAL===\n"; + +$it->rewind(); +while($it->valid()) +{ + echo $it->current() . "\n"; + $it->next(); + break; +} +$it->rewind(); +while($it->valid()) +{ + echo $it->current() . "\n"; + $it->next(); +} + +?> +===DONE=== + +--EXPECT-- +MyRecursiveIteratorIterator::beginIteration() +1 +2 +31 +32 +331 +4 +MyRecursiveIteratorIterator::endIteration() +===MORE=== +MyRecursiveIteratorIterator::beginIteration() +1 +2 +31 +32 +331 +4 +MyRecursiveIteratorIterator::endIteration() +===MORE=== +MyRecursiveIteratorIterator::beginIteration() +1 +2 +31 +32 +331 +4 +MyRecursiveIteratorIterator::endIteration() +bool(false) +===MANUAL=== +MyRecursiveIteratorIterator::beginIteration() +1 +1 +2 +31 +32 +331 +4 +MyRecursiveIteratorIterator::endIteration() +===DONE=== diff --git a/ext/spl/tests/iterator_026.phpt b/ext/spl/tests/iterator_026.phpt new file mode 100755 index 0000000000..100c2a49f7 --- /dev/null +++ b/ext/spl/tests/iterator_026.phpt @@ -0,0 +1,34 @@ +--TEST-- +SPL: CachingIterator::hasNext() +--FILE-- +$v) +{ + echo "$k=>$v\n"; + echo "hasNext: " . ($it->getInnerIterator()->hasNext() ? "yes" : "no") . "\n"; +} + +?> +===DONE=== + +--EXPECT-- +0=>1 +hasNext: yes +1=>2 +hasNext: yes +0=>31 +hasNext: yes +1=>32 +hasNext: yes +0=>331 +hasNext: no +3=>4 +hasNext: no +===DONE=== diff --git a/ext/spl/tests/iterator_027.phpt b/ext/spl/tests/iterator_027.phpt new file mode 100755 index 0000000000..fd9ba70c0f --- /dev/null +++ b/ext/spl/tests/iterator_027.phpt @@ -0,0 +1,83 @@ +--TEST-- +SPL: CachingIterator::FULL_CACHE +--FILE-- +$v) +{ + echo "$k=>$v\n"; +} + +echo "===CHECK===\n"; + +for ($i = 0; $i < 4; $i++) +{ + if (isset($it[$i])) + { + var_dump($i, $it[$i]); + } +} + +$it[2] = 'foo'; +$it[3] = 'bar'; +$it['baz'] = '25'; + +var_dump($it[2]); +var_dump($it[3]); +var_dump($it['baz']); + +unset($it[0]); +unset($it[2]); +unset($it['baz']); + +var_dump(isset($it[0])); // unset +var_dump(isset($it[1])); // still present +var_dump(isset($it[2])); // unset +var_dump(isset($it[3])); // still present +var_dump(isset($it['baz'])); + +echo "===REWIND===\n"; + +$it->rewind(); // cleans and reads first element +var_dump(isset($it[0])); // pre-fetched +var_dump(isset($it[1])); // deleted +var_dump(isset($it[2])); // unset +var_dump(isset($it[3])); // deleted + +?> +===DONE=== + +--EXPECT-- +0=>1 +1=>2 +0=>31 +1=>32 +0=>331 +3=>4 +===CHECK=== +int(0) +int(331) +int(1) +int(32) +int(3) +int(4) +string(3) "foo" +string(3) "bar" +string(2) "25" +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +===REWIND=== +bool(true) +bool(false) +bool(false) +bool(false) +===DONE===