Commit 4d528531be4 for php.net
commit 4d528531be4d944f888954099ac5b037a645cadf
Author: Gina Peter Banyard <girgias@php.net>
Date: Sat Mar 21 17:05:33 2026 +0000
ext/spl: extract AppendIterator constructor (#21367)
The implementation of it is simple whereas spl_dual_it_construct() is extremely convoluted
diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c
index a73e69519db..4f1a2a407be 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 610e056f538..c2b5885dd23 100644
--- a/ext/spl/tests/iterator_031.phpt
+++ b/ext/spl/tests/iterator_031.phpt
@@ -3,6 +3,13 @@
--FILE--
<?php
+$ap = new AppendIterator();
+try {
+ $ap->__construct();
+} catch (\Throwable $e) {
+ echo $e::class, ': ', $e->getMessage(), "\n";
+}
+
class MyArrayIterator extends ArrayIterator
{
function rewind(): void
@@ -14,8 +21,7 @@ function rewind(): void
$it = new MyArrayIterator(array(1,2));
-foreach($it as $k=>$v)
-{
+foreach($it as $k=>$v) {
echo "$k=>$v\n";
}
@@ -44,31 +50,24 @@ function append(Iterator $what): void
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 @@ function parent__construct()
$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