summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcus Boerger <helly@php.net>2006-03-05 17:39:49 +0000
committerMarcus Boerger <helly@php.net>2006-03-05 17:39:49 +0000
commit7dc322754a698bb716ebb6fcdfb8b8842e12d918 (patch)
treeac0576836a87c5a3187b0d817bbe490b5501f5e1
parent41de805a9d43ed9a6dbe351e5ed1aa1f52cb9641 (diff)
downloadphp-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-xext/spl/spl.php11
-rwxr-xr-xext/spl/spl_array.c9
-rwxr-xr-xext/spl/spl_directory.c59
-rwxr-xr-xext/spl/spl_engine.c14
-rwxr-xr-xext/spl/spl_engine.h2
-rwxr-xr-xext/spl/spl_iterators.c59
-rwxr-xr-xext/spl/spl_iterators.h4
-rwxr-xr-xext/spl/spl_sxe.c22
-rwxr-xr-xext/spl/tests/array_019.phpt32
-rwxr-xr-xext/spl/tests/iterator_030.phpt46
-rwxr-xr-xext/spl/tests/iterator_031.phpt118
-rwxr-xr-xext/spl/tests/iterator_032.phpt52
-rwxr-xr-xext/spl/tests/iterator_033.phpt46
-rwxr-xr-xext/spl/tests/iterator_034.phpt190
-rwxr-xr-xext/spl/tests/sxe_005.phpt46
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===