diff options
author | Marcus Boerger <helly@php.net> | 2006-03-05 17:39:49 +0000 |
---|---|---|
committer | Marcus Boerger <helly@php.net> | 2006-03-05 17:39:49 +0000 |
commit | 7dc322754a698bb716ebb6fcdfb8b8842e12d918 (patch) | |
tree | ac0576836a87c5a3187b0d817bbe490b5501f5e1 | |
parent | 41de805a9d43ed9a6dbe351e5ed1aa1f52cb9641 (diff) | |
download | php-git-7dc322754a698bb716ebb6fcdfb8b8842e12d918.tar.gz |
- Fix issues with not/double calling of constructors of SPL iterators
- Fix issues with info-class/file-class in SPL directory handling classes
- Add SimpleXMLElement::count()
- Drop erroneous RecursiveDirectoryIterator::getSubPathInfo()
- Drop dead code
- Add tests
- Update docu
-rwxr-xr-x | ext/spl/spl.php | 11 | ||||
-rwxr-xr-x | ext/spl/spl_array.c | 9 | ||||
-rwxr-xr-x | ext/spl/spl_directory.c | 59 | ||||
-rwxr-xr-x | ext/spl/spl_engine.c | 14 | ||||
-rwxr-xr-x | ext/spl/spl_engine.h | 2 | ||||
-rwxr-xr-x | ext/spl/spl_iterators.c | 59 | ||||
-rwxr-xr-x | ext/spl/spl_iterators.h | 4 | ||||
-rwxr-xr-x | ext/spl/spl_sxe.c | 22 | ||||
-rwxr-xr-x | ext/spl/tests/array_019.phpt | 32 | ||||
-rwxr-xr-x | ext/spl/tests/iterator_030.phpt | 46 | ||||
-rwxr-xr-x | ext/spl/tests/iterator_031.phpt | 118 | ||||
-rwxr-xr-x | ext/spl/tests/iterator_032.phpt | 52 | ||||
-rwxr-xr-x | ext/spl/tests/iterator_033.phpt | 46 | ||||
-rwxr-xr-x | ext/spl/tests/iterator_034.phpt | 190 | ||||
-rwxr-xr-x | ext/spl/tests/sxe_005.phpt | 46 |
15 files changed, 618 insertions, 92 deletions
diff --git a/ext/spl/spl.php b/ext/spl/spl.php index 4ba58fceb4..f704e044ba 100755 --- a/ext/spl/spl.php +++ b/ext/spl/spl.php @@ -887,8 +887,8 @@ class SplFileInfo */ function setFileClass(string class_name = "SplFileObject"); - /** @param class_name name of class used with getFileInfo(), getPathInfo(), - * getSubPathInfo(). Must be derived from SplFileInfo. + /** @param class_name name of class used with getFileInfo(), getPathInfo(). + * Must be derived from SplFileInfo. */ function setInfoClass(string class_name = "SplFileInfo"); } @@ -971,13 +971,6 @@ class RecursiveDirectoryIterator extends DirectoryIterator implements RecursiveI /** @return the current sub path */ function getSubPathname(); - - /** @return SplFileInfo created for the current sub path - * @param class_name name of class to instantiate - * @see SplFileInfo::setInfoClass() - */ - function getSubPathInfo(string $class_name = NULL); - } /** @ingroup SPL diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c index 9b31ea0e68..4414e48ea1 100755 --- a/ext/spl/spl_array.c +++ b/ext/spl/spl_array.c @@ -472,6 +472,7 @@ void spl_array_iterator_append(zval *object, zval *append_value TSRMLS_DC) /* {{ if (Z_TYPE_P(intern->array) == IS_OBJECT) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot append properties to objects, use %s::offsetSet() instead", Z_OBJCE_P(object)->name); + return; } spl_array_write_dimension(object, NULL, append_value TSRMLS_CC); @@ -701,7 +702,6 @@ static void spl_array_it_move_forward(zend_object_iterator *iter TSRMLS_DC) /* { { spl_array_it *iterator = (spl_array_it *)iter; spl_array_object *object = iterator->object; - HashTable *aht = spl_array_get_hash_table(object, 0 TSRMLS_CC); if (!aht) { @@ -909,8 +909,8 @@ SPL_METHOD(Array, exchangeArray) { zval *object = getThis(), *tmp, **array; spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); - - array_init(return_value); + + array_init(return_value); zend_hash_copy(HASH_OF(return_value), spl_array_get_hash_table(intern, 0 TSRMLS_CC), (copy_ctor_func_t) zval_add_ref, &tmp, sizeof(zval*)); if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &array) == FAILURE) { @@ -1195,7 +1195,7 @@ SPL_METHOD(Array, getChildren) if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) { return; } - + if (Z_TYPE_PP(entry) == IS_OBJECT && instanceof_function(Z_OBJCE_PP(entry), Z_OBJCE_P(getThis()) TSRMLS_CC)) { RETURN_ZVAL(*entry, 0, 0); } @@ -1303,6 +1303,7 @@ PHP_MINIT_FUNCTION(spl_array) REGISTER_SPL_IMPLEMENTS(ArrayObject, Aggregate); REGISTER_SPL_IMPLEMENTS(ArrayObject, ArrayAccess); memcpy(&spl_handler_ArrayObject, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + spl_handler_ArrayObject.clone_obj = spl_array_object_clone; spl_handler_ArrayObject.read_dimension = spl_array_read_dimension; spl_handler_ArrayObject.write_dimension = spl_array_write_dimension; diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index 8fa22fdb12..76b552ca85 100755 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -748,26 +748,30 @@ SPL_METHOD(SplFileInfo, setFileClass) spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); zend_class_entry *ce = spl_ce_SplFileObject; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|C", &ce) == FAILURE) { - return; + php_set_error_handling(EH_THROW, spl_ce_UnexpectedValueException TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|C", &ce) == SUCCESS) { + intern->file_class = ce; } - intern->file_class = ce; + php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC); } /* }}} */ /* {{{ proto SplFileObject SplFileInfo::setInfoClass([string class_name]) - Class to use in getFileInfo(), getPathInfo(), getSubPathInfo() */ + Class to use in getFileInfo(), getPathInfo() */ SPL_METHOD(SplFileInfo, setInfoClass) { spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); zend_class_entry *ce = spl_ce_SplFileInfo; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|C", &ce) == FAILURE) { - return; + php_set_error_handling(EH_THROW, spl_ce_UnexpectedValueException TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|C", &ce) == SUCCESS) { + intern->info_class = ce; } - intern->info_class = ce; + php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC); } /* }}} */ @@ -778,11 +782,13 @@ SPL_METHOD(SplFileInfo, getFileInfo) spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); zend_class_entry *ce = intern->info_class; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|C", &ce) == FAILURE) { - return; + php_set_error_handling(EH_THROW, spl_ce_UnexpectedValueException TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|C", &ce) == SUCCESS) { + spl_filesystem_object_create_type(ht, intern, SPL_FS_INFO, ce, return_value TSRMLS_CC); } - spl_filesystem_object_create_type(ht, intern, SPL_FS_INFO, ce, return_value TSRMLS_CC); + php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC); } /* }}} */ @@ -793,11 +799,13 @@ SPL_METHOD(SplFileInfo, getPathInfo) spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); zend_class_entry *ce = intern->info_class; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|C", &ce) == FAILURE) { - return; + php_set_error_handling(EH_THROW, spl_ce_UnexpectedValueException TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|C", &ce) == SUCCESS) { + spl_filesystem_object_create_info(intern, intern->path, intern->path_len, 1, ce, return_value TSRMLS_CC); } - spl_filesystem_object_create_info(intern, intern->path, intern->path_len, 1, ce, return_value TSRMLS_CC); + php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC); } /* }}} */ @@ -810,7 +818,7 @@ SPL_METHOD(RecursiveDirectoryIterator, __construct) int len; long flags = SPL_FILE_DIR_CURRENT_AS_FILEINFO; - php_set_error_handling(EH_THROW, spl_ce_RuntimeException TSRMLS_CC); + php_set_error_handling(EH_THROW, spl_ce_UnexpectedValueException TSRMLS_CC); if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &path, &len, &flags) == FAILURE) { php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC); @@ -950,28 +958,6 @@ SPL_METHOD(RecursiveDirectoryIterator, getSubPathname) } /* }}} */ -/* {{{ proto SplFileInfo RecursiveDirectoryIterator::getSubPathInfo([string $class_info]) - Create SplFileInfo for sub path */ -SPL_METHOD(RecursiveDirectoryIterator, getSubPathInfo) -{ - spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); - char *sub_name; - int len; - zend_class_entry *ce = intern->info_class; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|C", &ce) == FAILURE) { - return; - } - - if (intern->u.dir.sub_path) { - len = spprintf(&sub_name, 0, "%s%c%s", intern->u.dir.sub_path, DEFAULT_SLASH, intern->u.dir.entry.d_name); - spl_filesystem_object_create_info(intern, sub_name, len, 0, ce, return_value TSRMLS_CC); - } else { - spl_filesystem_object_create_info(intern, intern->path, intern->path_len, 1, ce, return_value TSRMLS_CC); - } -} -/* }}} */ - /* define an overloaded iterator structure */ typedef struct { zend_object_iterator intern; @@ -1329,7 +1315,6 @@ static zend_function_entry spl_RecursiveDirectoryIterator_functions[] = { SPL_ME(RecursiveDirectoryIterator, getChildren, NULL, ZEND_ACC_PUBLIC) SPL_ME(RecursiveDirectoryIterator, getSubPath, NULL, ZEND_ACC_PUBLIC) SPL_ME(RecursiveDirectoryIterator, getSubPathname,NULL, ZEND_ACC_PUBLIC) - SPL_ME(RecursiveDirectoryIterator, getSubPathInfo,arginfo_info_optinalFileClass, ZEND_ACC_PUBLIC) {NULL, NULL, NULL} }; diff --git a/ext/spl/spl_engine.c b/ext/spl/spl_engine.c index 2da47f7d34..5e09f2b495 100755 --- a/ext/spl/spl_engine.c +++ b/ext/spl/spl_engine.c @@ -43,20 +43,6 @@ void spl_instantiate(zend_class_entry *pce, zval **object, int alloc TSRMLS_DC) } /* }}} */ -/* {{{ spl_is_instance_of */ -int spl_is_instance_of(zval **obj, zend_class_entry *ce TSRMLS_DC) -{ - /* Ensure everything needed is available before checking for the type. - */ - zend_class_entry *instance_ce; - - if (obj && (instance_ce = spl_get_class_entry(*obj TSRMLS_CC)) != NULL) { - return instanceof_function(instance_ce, ce TSRMLS_CC); - } - return 0; -} -/* }}} */ - /* * Local variables: * tab-width: 4 diff --git a/ext/spl/spl_engine.h b/ext/spl/spl_engine.h index 860659e603..36ce184181 100755 --- a/ext/spl/spl_engine.h +++ b/ext/spl/spl_engine.h @@ -58,8 +58,6 @@ static inline int spl_instantiate_arg_ex2(zend_class_entry *pce, zval **retval, } /* }}} */ -int spl_is_instance_of(zval **obj, zend_class_entry *ce TSRMLS_DC); - #endif /* SPL_ENGINE_H */ /* diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c index 4d4b4e331a..50998424ed 100755 --- a/ext/spl/spl_iterators.c +++ b/ext/spl/spl_iterators.c @@ -815,18 +815,32 @@ int spl_dual_it_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS) } #endif +#define SPL_CHECK_CTOR(intern, classname) \ + if (intern->dit_type == DIT_Unknown) { \ + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Classes derived from %v must call %v::__construct()", \ + (spl_ce_##classname)->name, (spl_ce_##classname)->name); \ + return; \ + } + +#define APPENDIT_CHECK_CTOR(intern) SPL_CHECK_CTOR(intern, AppendIterator) + static inline int spl_dual_it_fetch(spl_dual_it_object *intern, int check_more TSRMLS_DC); -static inline spl_dual_it_object* spl_dual_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *ce_inner, dual_it_type dit_type) +static spl_dual_it_object* spl_dual_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *ce_base, zend_class_entry *ce_inner, dual_it_type dit_type) { zval *zobject, *retval; spl_dual_it_object *intern; zend_class_entry *ce = NULL; int inc_refcount = 1; - php_set_error_handling(EH_THROW, spl_ce_InvalidArgumentException TSRMLS_CC); - intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (intern->dit_type != DIT_Unknown) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%v::getIterator() must be called exactly once per instance", ce_base->name); + return NULL; + } + + php_set_error_handling(EH_THROW, spl_ce_InvalidArgumentException TSRMLS_CC); intern->dit_type = dit_type; switch (dit_type) { @@ -931,9 +945,9 @@ static inline spl_dual_it_object* spl_dual_it_construct(INTERNAL_FUNCTION_PARAME /* {{{ proto FilterIterator::__construct(Iterator it) Create an Iterator from another iterator */ -SPL_METHOD(dual_it, __construct) +SPL_METHOD(FilterIterator, __construct) { - spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, zend_ce_iterator, DIT_Default); + spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_FilterIterator, zend_ce_iterator, DIT_FilterIterator); } /* }}} */ /* {{{ proto Iterator FilterIterator::getInnerIterator() @@ -1173,7 +1187,7 @@ SPL_METHOD(FilterIterator, next) Create a RecursiveFilterIterator from a RecursiveIterator */ SPL_METHOD(RecursiveFilterIterator, __construct) { - spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveIterator, DIT_Default); + spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveFilterIterator, spl_ce_RecursiveIterator, DIT_RecursiveFilterIterator); } /* }}} */ /* {{{ proto boolean RecursiveFilterIterator::hasChildren() @@ -1199,7 +1213,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(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); } /* }}} */ @@ -1207,7 +1221,7 @@ SPL_METHOD(RecursiveFilterIterator, getChildren) Create a ParentIterator from a RecursiveIterator */ SPL_METHOD(ParentIterator, __construct) { - spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveIterator, DIT_Default); + spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_ParentIterator, spl_ce_RecursiveIterator, DIT_ParentIterator); } /* }}} */ /* {{{ proto boolean ParentIterator::hasChildren() @@ -1233,7 +1247,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(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); } /* }}} */ @@ -1274,6 +1288,7 @@ static zend_object_value spl_dual_it_new(zend_class_entry *class_type TSRMLS_DC) intern = emalloc(sizeof(spl_dual_it_object)); memset(intern, 0, sizeof(spl_dual_it_object)); intern->std.ce = class_type; + intern->dit_type = DIT_Unknown; ALLOC_HASHTABLE(intern->std.properties); zend_hash_init(intern->std.properties, 0, NULL, ZVAL_PTR_DTOR, 0); @@ -1291,7 +1306,7 @@ ZEND_BEGIN_ARG_INFO(arginfo_filter_it___construct, 0) ZEND_END_ARG_INFO(); static zend_function_entry spl_funcs_FilterIterator[] = { - SPL_ME(dual_it, __construct, arginfo_filter_it___construct, ZEND_ACC_PUBLIC) + SPL_ME(FilterIterator, __construct, arginfo_filter_it___construct, ZEND_ACC_PUBLIC) SPL_ME(FilterIterator, rewind, NULL, ZEND_ACC_PUBLIC) SPL_ME(dual_it, valid, NULL, ZEND_ACC_PUBLIC) SPL_ME(dual_it, key, NULL, ZEND_ACC_PUBLIC) @@ -1343,7 +1358,7 @@ static inline void spl_limit_it_seek(spl_dual_it_object *intern, long pos TSRMLS zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0 TSRMLS_CC, "Cannot seek to %ld which is below the offset %ld", pos, intern->u.limit.offset); return; } - if (pos > intern->u.limit.offset + intern->u.limit.count && intern->u.limit.count != -1) { + if (pos >= intern->u.limit.offset + intern->u.limit.count && intern->u.limit.count != -1) { zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0 TSRMLS_CC, "Cannot seek to %ld which is behind offest %ld plus count %ld", pos, intern->u.limit.offset, intern->u.limit.count); return; } @@ -1376,7 +1391,7 @@ static inline void spl_limit_it_seek(spl_dual_it_object *intern, long pos TSRMLS Construct a LimitIterator from an Iterator with a given starting offset and optionally a maximum count */ SPL_METHOD(LimitIterator, __construct) { - spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, zend_ce_iterator, DIT_LimitIterator); + spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_LimitIterator, zend_ce_iterator, DIT_LimitIterator); } /* }}} */ /* {{{ proto void LimitIterator::rewind() @@ -1568,7 +1583,7 @@ static inline void spl_caching_it_rewind(spl_dual_it_object *intern TSRMLS_DC) Construct a CachingIterator from an Iterator */ SPL_METHOD(CachingIterator, __construct) { - spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, zend_ce_iterator, DIT_CachingIterator); + spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_CachingIterator, zend_ce_iterator, DIT_CachingIterator); } /* }}} */ /* {{{ proto void CachingIterator::rewind() @@ -1669,7 +1684,7 @@ static zend_function_entry spl_funcs_CachingIterator[] = { Create an iterator from a RecursiveIterator */ SPL_METHOD(RecursiveCachingIterator, __construct) { - spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveIterator, DIT_RecursiveCachingIterator); + spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveCachingIterator, spl_ce_RecursiveIterator, DIT_RecursiveCachingIterator); } /* }}} */ /* {{{ proto bolean RecursiveCachingIterator::hasChildren() @@ -1715,7 +1730,7 @@ static zend_function_entry spl_funcs_RecursiveCachingIterator[] = { Create an iterator from anything that is traversable */ SPL_METHOD(IteratorIterator, __construct) { - spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, zend_ce_traversable, DIT_IteratorIterator); + spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_IteratorIterator, zend_ce_traversable, DIT_IteratorIterator); } /* }}} */ static @@ -1738,7 +1753,7 @@ static zend_function_entry spl_funcs_IteratorIterator[] = { Create an iterator from another iterator */ SPL_METHOD(NoRewindIterator, __construct) { - spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, zend_ce_iterator, DIT_NoRewindIterator); + spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_NoRewindIterator, zend_ce_iterator, DIT_NoRewindIterator); } /* }}} */ /* {{{ proto void NoRewindIterator::rewind() @@ -1822,7 +1837,7 @@ static zend_function_entry spl_funcs_NoRewindIterator[] = { Create an iterator from another iterator */ SPL_METHOD(InfiniteIterator, __construct) { - spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, zend_ce_iterator, DIT_InfiniteIterator); + spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_InfiniteIterator, zend_ce_iterator, DIT_InfiniteIterator); } /* }}} */ /* {{{ proto InfiniteIterator::next() @@ -1916,7 +1931,6 @@ int spl_append_it_next_iterator(spl_dual_it_object *intern TSRMLS_DC) /* {{{*/ intern->inner.object = zend_object_store_get_object(*it TSRMLS_CC); intern->inner.iterator = intern->inner.ce->get_iterator(intern->inner.ce, *it TSRMLS_CC); spl_dual_it_rewind(intern TSRMLS_CC); - intern->u.append.iterator->funcs->move_forward(intern->u.append.iterator TSRMLS_CC); return SUCCESS; } else { return FAILURE; @@ -1926,6 +1940,7 @@ int spl_append_it_next_iterator(spl_dual_it_object *intern TSRMLS_DC) /* {{{*/ void spl_append_it_fetch(spl_dual_it_object *intern TSRMLS_DC) /* {{{*/ { while (spl_dual_it_valid(intern TSRMLS_CC) != SUCCESS) { + intern->u.append.iterator->funcs->move_forward(intern->u.append.iterator TSRMLS_CC); if (spl_append_it_next_iterator(intern TSRMLS_CC) != SUCCESS) { return; } @@ -1945,7 +1960,7 @@ void spl_append_it_next(spl_dual_it_object *intern TSRMLS_DC) /* {{{ */ Create an AppendIterator */ SPL_METHOD(AppendIterator, __construct) { - spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, zend_ce_iterator, DIT_AppendIterator); + spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_AppendIterator, zend_ce_iterator, DIT_AppendIterator); } /* }}} */ /* {{{ proto void AppendIterator::append(Iterator it) @@ -1956,8 +1971,10 @@ SPL_METHOD(AppendIterator, append) zval *it; intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + APPENDIT_CHECK_CTOR(intern); - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &it, zend_ce_iterator) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &it, zend_ce_iterator) == FAILURE) { return; } spl_array_iterator_append(intern->u.append.zarrayit, it TSRMLS_CC); @@ -2071,7 +2088,7 @@ PHP_FUNCTION(iterator_to_array) } /* }}} */ -/* {{{ int iterator_count(Travesable it) +/* {{{ int iterator_count(Traversable it) Count the elements in an iterator */ PHP_FUNCTION(iterator_count) { diff --git a/ext/spl/spl_iterators.h b/ext/spl/spl_iterators.h index 5ddd819790..5bb8136493 100755 --- a/ext/spl/spl_iterators.h +++ b/ext/spl/spl_iterators.h @@ -53,6 +53,9 @@ PHP_FUNCTION(iterator_count); typedef enum { DIT_Default = 0, + DIT_FilterIterator = DIT_Default, + DIT_RecursiveFilterIterator = DIT_Default, + DIT_ParentIterator = DIT_Default, DIT_LimitIterator, DIT_CachingIterator, DIT_RecursiveCachingIterator, @@ -60,6 +63,7 @@ typedef enum { DIT_NoRewindIterator, DIT_InfiniteIterator, DIT_AppendIterator, + DIT_Unknown = ~0 } dual_it_type; enum { diff --git a/ext/spl/spl_sxe.c b/ext/spl/spl_sxe.c index 339880534f..b1d4dd393f 100755 --- a/ext/spl/spl_sxe.c +++ b/ext/spl/spl_sxe.c @@ -32,6 +32,7 @@ #include "spl_engine.h" #include "spl_iterators.h" #include "spl_sxe.h" +#include "spl_array.h" zend_class_entry *spl_ce_SimpleXMLIterator = NULL; zend_class_entry *spl_ce_SimpleXMLElement; @@ -85,7 +86,7 @@ SPL_METHOD(SimpleXMLIterator, key) /* {{{ */ RETURN_STRINGL((char*)curnode->name, xmlStrlen(curnode->name), 1); } - RETURN_FALSE; + RETURN_FALSE; } /* }}} */ @@ -106,7 +107,7 @@ SPL_METHOD(SimpleXMLIterator, hasChildren) php_sxe_object *child; xmlNodePtr node; - if (!sxe->iter.data) { + if (!sxe->iter.data || sxe->iter.type == SXE_ITER_ATTRLIST) { RETURN_FALSE; } child = php_sxe_fetch_object(sxe->iter.data TSRMLS_CC); @@ -128,13 +129,22 @@ SPL_METHOD(SimpleXMLIterator, getChildren) { php_sxe_object *sxe = php_sxe_fetch_object(getThis() TSRMLS_CC); - if (!sxe->iter.data) { + if (!sxe->iter.data || sxe->iter.type == SXE_ITER_ATTRLIST) { return; /* return NULL */ } return_value->type = IS_OBJECT; return_value->value.obj = zend_objects_store_clone_obj(sxe->iter.data TSRMLS_CC); } +SPL_METHOD(SimpleXMLIterator, count) /* {{{ */ +{ + long count = 0; + + Z_OBJ_HANDLER_P(getThis(), count_elements)(getThis(), &count TSRMLS_CC); + + RETURN_LONG(count); +} + static zend_function_entry spl_funcs_SimpleXMLIterator[] = { SPL_ME(SimpleXMLIterator, rewind, NULL, ZEND_ACC_PUBLIC) SPL_ME(SimpleXMLIterator, valid, NULL, ZEND_ACC_PUBLIC) @@ -143,6 +153,7 @@ static zend_function_entry spl_funcs_SimpleXMLIterator[] = { SPL_ME(SimpleXMLIterator, next, NULL, ZEND_ACC_PUBLIC) SPL_ME(SimpleXMLIterator, hasChildren, NULL, ZEND_ACC_PUBLIC) SPL_ME(SimpleXMLIterator, getChildren, NULL, ZEND_ACC_PUBLIC) + SPL_ME(SimpleXMLIterator, count, NULL, ZEND_ACC_PUBLIC) {NULL, NULL, NULL} }; /* }}} */ @@ -150,17 +161,18 @@ static zend_function_entry spl_funcs_SimpleXMLIterator[] = { SPL_API PHP_MINIT_FUNCTION(spl_sxe) /* {{{ */ { zend_class_entry **pce; - + if (zend_hash_find(CG(class_table), "simplexmlelement", sizeof("SimpleXMLElement"), (void **) &pce) == FAILURE) { spl_ce_SimpleXMLElement = NULL; spl_ce_SimpleXMLIterator = NULL; return SUCCESS; /* SimpleXML must be initialized before */ } - + spl_ce_SimpleXMLElement = *pce; REGISTER_SPL_SUB_CLASS_EX(SimpleXMLIterator, SimpleXMLElement, spl_ce_SimpleXMLElement->create_object, spl_funcs_SimpleXMLIterator); REGISTER_SPL_IMPLEMENTS(SimpleXMLIterator, RecursiveIterator); + REGISTER_SPL_IMPLEMENTS(SimpleXMLIterator, Countable); return SUCCESS; } diff --git a/ext/spl/tests/array_019.phpt b/ext/spl/tests/array_019.phpt new file mode 100755 index 0000000000..1416d8407d --- /dev/null +++ b/ext/spl/tests/array_019.phpt @@ -0,0 +1,32 @@ +--TEST-- +SPL: ArrayIterator and foreach by reference +--SKIPIF-- +<?php if (!extension_loaded("spl")) print "skip"; ?> +--FILE-- +<?php + +$ar = new ArrayObject(array(1)); foreach($ar as &$v) var_dump($v); +$ar = new ArrayIterator(array(2)); foreach($ar as &$v) var_dump($v); +$ar = new RecursiveArrayIterator(array(3)); foreach($ar as &$v) var_dump($v); + +class ArrayIteratorEx extends ArrayIterator +{ + function current() + { + return ArrayIterator::current(); + } +} + +$ar = new ArrayIteratorEx(array(4)); foreach($ar as $v) var_dump($v); +$ar = new ArrayIteratorEx(array(5)); foreach($ar as &$v) var_dump($v); + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +int(1) +int(2) +int(3) +int(4) +int(5) +===DONE=== diff --git a/ext/spl/tests/iterator_030.phpt b/ext/spl/tests/iterator_030.phpt new file mode 100755 index 0000000000..6ed8035ac1 --- /dev/null +++ b/ext/spl/tests/iterator_030.phpt @@ -0,0 +1,46 @@ +--TEST-- +SPL: EmptyIterator access +--SKIPIF-- +<?php if (!extension_loaded("spl")) print "skip"; ?> +--FILE-- +<?php + +$it = new EmptyIterator; + +var_dump($it->valid()); +$it->rewind(); +var_dump($it->valid()); +$it->next(); +var_dump($it->valid()); + +try +{ + var_dump($it->key()); +} +catch(BadMethodCallException $e) +{ + echo $e->getMessage() . "\n"; +} + +try +{ + var_dump($it->current()); +} +catch(BadMethodCallException $e) +{ + echo $e->getMessage() . "\n"; +} + +var_dump($it->valid()); + +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +bool(false) +bool(false) +bool(false) +Accessing the key of an EmptyIterator +Accessing the value of an EmptyIterator +bool(false) +===DONE=== diff --git a/ext/spl/tests/iterator_031.phpt b/ext/spl/tests/iterator_031.phpt new file mode 100755 index 0000000000..00afa61850 --- /dev/null +++ b/ext/spl/tests/iterator_031.phpt @@ -0,0 +1,118 @@ +--TEST-- +SPL: AppendIterator::append() rewinds when neccessary +--SKIPIF-- +<?php if (!extension_loaded("spl")) print "skip"; ?> +--FILE-- +<?php + +class MyArrayIterator extends ArrayIterator +{ + function rewind() + { + echo __METHOD__ . "\n"; + parent::rewind(); + } +} + +$it = new MyArrayIterator(array(1,2)); + +foreach($it as $k=>$v) +{ + echo "$k=>$v\n"; +} + +class MyAppendIterator extends AppendIterator +{ + function __construct() + { + echo __METHOD__ . "\n"; + } + + function rewind() + { + echo __METHOD__ . "\n"; + parent::rewind(); + } + + function valid() + { + echo __METHOD__ . "\n"; + return parent::valid(); + } + + function append(Iterator $what) + { + echo __METHOD__ . "\n"; + parent::append($what); + } + + function parent__construct() + { + parent::__construct(); + } +} + +$ap = new MyAppendIterator; + +try +{ + $ap->append($it); +} +catch(BadMethodCallException $e) +{ + echo $e->getMessage() . "\n"; +} + +$ap->parent__construct(); + +try +{ + $ap->parent__construct($it); +} +catch(BadMethodCallException $e) +{ + echo $e->getMessage() . "\n"; +} + +$ap->append($it); +$ap->append($it); +$ap->append($it); + +foreach($ap as $k=>$v) +{ + echo "$k=>$v\n"; +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +MyArrayIterator::rewind +0=>1 +1=>2 +MyAppendIterator::__construct +MyAppendIterator::append +Classes derived from AppendIterator must call AppendIterator::__construct() +AppendIterator::getIterator() must be called exactly once per instance +MyAppendIterator::append +MyArrayIterator::rewind +MyAppendIterator::append +MyAppendIterator::append +MyAppendIterator::rewind +MyArrayIterator::rewind +MyAppendIterator::valid +0=>1 +MyAppendIterator::valid +1=>2 +MyArrayIterator::rewind +MyAppendIterator::valid +0=>1 +MyAppendIterator::valid +1=>2 +MyArrayIterator::rewind +MyAppendIterator::valid +0=>1 +MyAppendIterator::valid +1=>2 +MyAppendIterator::valid +===DONE=== diff --git a/ext/spl/tests/iterator_032.phpt b/ext/spl/tests/iterator_032.phpt new file mode 100755 index 0000000000..86695d4af8 --- /dev/null +++ b/ext/spl/tests/iterator_032.phpt @@ -0,0 +1,52 @@ +--TEST-- +SPL: LimitIterator::getPosition() +--SKIPIF-- +<?php if (!extension_loaded("spl")) print "skip"; ?> +--FILE-- +<?php + +$it = new LimitIterator(new ArrayIterator(array(1,2,3,4)), 1, 2); + +foreach($it as $k=>$v) +{ + echo "$k=>$v\n"; + var_dump($it->getPosition()); +} + +try +{ + $it->seek(0); +} +catch(OutOfBoundsException $e) +{ + echo $e->getMessage() . "\n"; +} + +$it->seek(2); +var_dump($it->current()); + +try +{ + $it->seek(3); +} +catch(OutOfBoundsException $e) +{ + echo $e->getMessage() . "\n"; +} + +$it->next(); +var_dump($it->valid()); + +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +1=>2 +int(1) +2=>3 +int(2) +Cannot seek to 0 which is below the offset 1 +int(3) +Cannot seek to 3 which is behind offest 1 plus count 2 +bool(false) +===DONE=== diff --git a/ext/spl/tests/iterator_033.phpt b/ext/spl/tests/iterator_033.phpt new file mode 100755 index 0000000000..c1880cb2fb --- /dev/null +++ b/ext/spl/tests/iterator_033.phpt @@ -0,0 +1,46 @@ +--TEST-- +SPL: ParentIterator +--SKIPIF-- +<?php if (!extension_loaded("spl")) print "skip"; ?> +--FILE-- +<?php + +$it = new ParentIterator(new RecursiveArrayIterator(array(1,array(21,22, array(231)),3))); + +foreach(new RecursiveIteratorIterator($it) as $k=>$v) +{ + var_dump($k); + var_dump($v); +} + +echo "==SECOND==\n"; + +foreach(new RecursiveIteratorIterator($it, 1) as $k=>$v) +{ + var_dump($k); + var_dump($v); +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +==SECOND== +int(1) +array(3) { + [0]=> + int(21) + [1]=> + int(22) + [2]=> + array(1) { + [0]=> + int(231) + } +} +int(2) +array(1) { + [0]=> + int(231) +} +===DONE=== diff --git a/ext/spl/tests/iterator_034.phpt b/ext/spl/tests/iterator_034.phpt new file mode 100755 index 0000000000..b81c6d970e --- /dev/null +++ b/ext/spl/tests/iterator_034.phpt @@ -0,0 +1,190 @@ +--TEST-- +SPL: RecursiveIteratorIterator and break deep +--SKIPIF-- +<?php if (!extension_loaded("spl")) print "skip"; ?> +--FILE-- +<?php + +class MyRecursiveArrayIterator extends RecursiveArrayIterator +{ + function valid() + { + if (!parent::valid()) + { + echo __METHOD__ . "() = false\n"; + return false; + } + else + { + return true; + } + } + + function getChildren() + { + echo __METHOD__ . "()\n"; + return parent::getChildren(); + } + + function rewind() + { + echo __METHOD__ . "()\n"; + parent::rewind(); + } +} + +class RecursiveArrayIteratorIterator extends RecursiveIteratorIterator +{ + private $max_depth; + private $over = 0; + + function __construct($it, $max_depth) + { + $this->max_depth = $max_depth; + parent::__construct($it); + } + + function rewind() + { + echo __METHOD__ . "() - BEGIN\n"; + parent::rewind(); + echo __METHOD__ . "() - DONE\n"; + } + + function valid() + { + echo __METHOD__ . "()\n"; + return parent::valid(); + } + + function current() + { + echo __METHOD__ . "()\n"; + return parent::current(); + } + + function key() + { + echo __METHOD__ . "()\n"; + return parent::key(); + } + + function next() + { + echo __METHOD__ . "()\n"; + parent::next(); + } + + function callHasChildren() + { + $has = parent::callHasChildren(); + $res = $this->getDepth() < $this->max_depth && $has; + echo __METHOD__ . "(".$this->getDepth().") = ".($res?"yes":"no")."/".($has?"yes":"no")."\n"; + return $res; + } + + function beginChildren() + { + echo __METHOD__ . "(".$this->getDepth().")\n"; + parent::beginChildren(); + } + + function endChildren() + { + echo __METHOD__ . "(".$this->getDepth().")\n"; + parent::endChildren(); + } +} + +$p = 0; +$it = new RecursiveArrayIteratorIterator(new MyRecursiveArrayIterator(array("a", array("ba", array("bba", "bbb"), array(array("bcaa"), array("bcba"))), array("ca"), "d")), 2); +foreach($it as $k=>$v) +{ + if (is_array($v)) $v = join('',$v); + echo "$k=>$v\n"; + if ($p++ == 5) + { + echo "===BREAK===\n"; + break; + } +} + +echo "===FOREND===\n"; + +$it->rewind(); + +echo "===CHECK===\n"; + +var_dump($it->valid()); +var_dump($it->current() == "a"); + +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +RecursiveArrayIteratorIterator::rewind() - BEGIN +MyRecursiveArrayIterator::rewind() +RecursiveArrayIteratorIterator::callHasChildren(0) = no/no +RecursiveArrayIteratorIterator::rewind() - DONE +RecursiveArrayIteratorIterator::valid() +RecursiveArrayIteratorIterator::current() +RecursiveArrayIteratorIterator::key() +0=>a +RecursiveArrayIteratorIterator::next() +RecursiveArrayIteratorIterator::callHasChildren(0) = yes/yes +MyRecursiveArrayIterator::getChildren() +MyRecursiveArrayIterator::rewind() +RecursiveArrayIteratorIterator::beginChildren(1) +RecursiveArrayIteratorIterator::callHasChildren(1) = no/no +RecursiveArrayIteratorIterator::valid() +RecursiveArrayIteratorIterator::current() +RecursiveArrayIteratorIterator::key() +0=>ba +RecursiveArrayIteratorIterator::next() +RecursiveArrayIteratorIterator::callHasChildren(1) = yes/yes +MyRecursiveArrayIterator::getChildren() +MyRecursiveArrayIterator::rewind() +RecursiveArrayIteratorIterator::beginChildren(2) +RecursiveArrayIteratorIterator::callHasChildren(2) = no/no +RecursiveArrayIteratorIterator::valid() +RecursiveArrayIteratorIterator::current() +RecursiveArrayIteratorIterator::key() +0=>bba +RecursiveArrayIteratorIterator::next() +RecursiveArrayIteratorIterator::callHasChildren(2) = no/no +RecursiveArrayIteratorIterator::valid() +RecursiveArrayIteratorIterator::current() +RecursiveArrayIteratorIterator::key() +1=>bbb +RecursiveArrayIteratorIterator::next() +MyRecursiveArrayIterator::valid() = false +RecursiveArrayIteratorIterator::endChildren(2) +RecursiveArrayIteratorIterator::callHasChildren(1) = yes/yes +MyRecursiveArrayIterator::getChildren() +MyRecursiveArrayIterator::rewind() +RecursiveArrayIteratorIterator::beginChildren(2) +RecursiveArrayIteratorIterator::callHasChildren(2) = no/yes +RecursiveArrayIteratorIterator::valid() +RecursiveArrayIteratorIterator::current() +RecursiveArrayIteratorIterator::key() +0=>bcaa +RecursiveArrayIteratorIterator::next() +RecursiveArrayIteratorIterator::callHasChildren(2) = no/yes +RecursiveArrayIteratorIterator::valid() +RecursiveArrayIteratorIterator::current() +RecursiveArrayIteratorIterator::key() +1=>bcba +===BREAK=== +===FOREND=== +RecursiveArrayIteratorIterator::rewind() - BEGIN +RecursiveArrayIteratorIterator::endChildren(1) +RecursiveArrayIteratorIterator::endChildren(0) +MyRecursiveArrayIterator::rewind() +RecursiveArrayIteratorIterator::callHasChildren(0) = no/no +RecursiveArrayIteratorIterator::rewind() - DONE +===CHECK=== +RecursiveArrayIteratorIterator::valid() +bool(true) +RecursiveArrayIteratorIterator::current() +bool(true) +===DONE=== diff --git a/ext/spl/tests/sxe_005.phpt b/ext/spl/tests/sxe_005.phpt new file mode 100755 index 0000000000..2efd0a6bee --- /dev/null +++ b/ext/spl/tests/sxe_005.phpt @@ -0,0 +1,46 @@ +--TEST-- +SPL: SimpleXMLIterator and getChildren() +--SKIPIF-- +<?php +if (!extension_loaded("spl")) print "skip"; +if (!extension_loaded('simplexml')) print 'skip'; +if (!extension_loaded("libxml")) print "skip LibXML not present"; +if (!class_exists('RecursiveIteratorIterator')) print 'skip RecursiveIteratorIterator not available'; +?> +--FILE-- +<?php + +$xml =<<<EOF +<?xml version='1.0'?> +<sxe> + <elem1/> + <elem2/> + <elem2/> +</sxe> +EOF; + +class SXETest extends SimpleXMLIterator +{ + function count() + { + echo __METHOD__ . "\n"; + return parent::count(); + } +} + +$sxe = new SXETest($xml); + +var_dump(count($sxe)); +var_dump(count($sxe->elem1)); +var_dump(count($sxe->elem2)); + +?> +===DONE=== +--EXPECT-- +SXETest::count +int(3) +SXETest::count +int(1) +SXETest::count +int(2) +===DONE=== |