From 297d5487cce9dc9eb34f887a97cfd8e68758f003 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Fri, 6 Mar 2026 23:04:41 +0000 Subject: [PATCH] ext/spl: extract AppendIterator constructor The implementation of it is simple whereas spl_dual_it_construct() is extremely convoluted --- ext/spl/spl_iterators.c | 25 +++++++++++++++---------- ext/spl/tests/iterator_031.phpt | 31 +++++++++++++++---------------- 2 files changed, 30 insertions(+), 26 deletions(-) diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c index a73e69519db51..4f1a2a407befc 100644 --- a/ext/spl/spl_iterators.c +++ b/ext/spl/spl_iterators.c @@ -1341,15 +1341,6 @@ static spl_dual_it_object* spl_dual_it_construct(INTERNAL_FUNCTION_PARAMETERS, z } break; } - case DIT_AppendIterator: - if (zend_parse_parameters_none() == FAILURE) { - return NULL; - } - intern->dit_type = DIT_AppendIterator; - object_init_ex(&intern->u.append.zarrayit, spl_ce_ArrayIterator); - zend_call_method_with_0_params(Z_OBJ(intern->u.append.zarrayit), spl_ce_ArrayIterator, &spl_ce_ArrayIterator->constructor, "__construct", NULL); - intern->u.append.iterator = spl_ce_ArrayIterator->get_iterator(spl_ce_ArrayIterator, &intern->u.append.zarrayit, 0); - return intern; case DIT_RegexIterator: case DIT_RecursiveRegexIterator: { zend_string *regex; @@ -2814,7 +2805,21 @@ static void spl_append_it_next(spl_dual_it_object *intern) /* {{{ */ /* {{{ Create an AppendIterator */ PHP_METHOD(AppendIterator, __construct) { - spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_AppendIterator, zend_ce_iterator, DIT_AppendIterator); + ZEND_PARSE_PARAMETERS_NONE(); + + spl_dual_it_object *intern = Z_SPLDUAL_IT_P(ZEND_THIS); + + /* TODO: This should be converted to a normal Error as this is triggered when calling the constructor twice */ + if (intern->dit_type != DIT_Unknown) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%s::getIterator() must be called exactly once per instance", ZSTR_VAL(spl_ce_AppendIterator->name)); + RETURN_THROWS(); + } + + intern->dit_type = DIT_AppendIterator; + object_init_ex(&intern->u.append.zarrayit, spl_ce_ArrayIterator); + zend_call_method_with_0_params(Z_OBJ(intern->u.append.zarrayit), spl_ce_ArrayIterator, &spl_ce_ArrayIterator->constructor, "__construct", NULL); + intern->u.append.iterator = spl_ce_ArrayIterator->get_iterator(spl_ce_ArrayIterator, &intern->u.append.zarrayit, 0); + } /* }}} */ /* {{{ Append an iterator */ diff --git a/ext/spl/tests/iterator_031.phpt b/ext/spl/tests/iterator_031.phpt index 610e056f53801..c2b5885dd23eb 100644 --- a/ext/spl/tests/iterator_031.phpt +++ b/ext/spl/tests/iterator_031.phpt @@ -3,6 +3,13 @@ SPL: AppendIterator::append() rewinds when necessary --FILE-- __construct(); +} catch (\Throwable $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} + class MyArrayIterator extends ArrayIterator { function rewind(): void @@ -14,8 +21,7 @@ class MyArrayIterator extends ArrayIterator $it = new MyArrayIterator(array(1,2)); -foreach($it as $k=>$v) -{ +foreach($it as $k=>$v) { echo "$k=>$v\n"; } @@ -44,31 +50,24 @@ class MyAppendIterator extends AppendIterator parent::append($what); } - function parent__construct() - { + function parent__construct() { parent::__construct(); } } $ap = new MyAppendIterator; -try -{ +try { $ap->append($it); -} -catch(\Error $e) -{ +} catch(\Error $e) { echo $e->getMessage() . "\n"; } $ap->parent__construct(); -try -{ +try { $ap->parent__construct($it); -} -catch(BadMethodCallException $e) -{ +} catch(BadMethodCallException $e) { echo $e->getMessage() . "\n"; } @@ -76,13 +75,13 @@ $ap->append($it); $ap->append($it); $ap->append($it); -foreach($ap as $k=>$v) -{ +foreach($ap as $k=>$v) { echo "$k=>$v\n"; } ?> --EXPECT-- +BadMethodCallException: AppendIterator::getIterator() must be called exactly once per instance MyArrayIterator::rewind 0=>1 1=>2