Commit 41ecd7c9ec4 for php
commit 41ecd7c9ec473e2fe24bead9ec0f68ee99db7f5c
Author: Nicolas Grekas <nicolas.grekas@gmail.com>
Date: Sun Sep 27 21:42:19 2026 +0200
ext/spl: Use fast ZPP in hot ArrayObject and ArrayIterator methods (#23946)
`return new \ArrayIterator($this->items);` is the usual getIterator() implementation of Twig nodes, Symfony bags or Doctrine collections, and profiling a foreach over such objects shows zend_parse_parameters() taking about 180 instructions per ArrayIterator::__construct() call. This switches both constructors and the ArrayAccess methods (offsetExists(), offsetGet(), offsetSet(), offsetUnset(), append()) to fast ZPP. Accepted types, error messages and deprecations don't change.
Instructions per operation (callgrind, -O2 build, arrays of 0/5/100 elements): new ArrayIterator() -181, i.e. -16.5%/-13.8%/-6.6%, and -11.4%/-4.7%/-0.4% when followed by foreach. new ArrayObject() -199, i.e. -17.8%/-14.9%/-7.2%, and -8.7%/-4.2%/-0.4% with foreach. offsetGet() and friends called as methods, e.g. via parent::offsetSet() in subclasses, are 39% to 43% cheaper. Walking Twig's node trees with foreach (17.6k nodes): -4.2% per round. The binary grows by 472 bytes of text.
diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c
index af603f3abf6..5b05e660931 100644
--- a/ext/spl/spl_array.c
+++ b/ext/spl/spl_array.c
@@ -643,9 +643,9 @@ static int spl_array_has_dimension(zend_object *object, zval *offset, int check_
PHP_METHOD(ArrayObject, offsetExists)
{
zval *index;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &index) == FAILURE) {
- RETURN_THROWS();
- }
+ ZEND_PARSE_PARAMETERS_START(1, 1)
+ Z_PARAM_ZVAL(index)
+ ZEND_PARSE_PARAMETERS_END();
RETURN_BOOL(spl_array_has_dimension_ex(/* check_inherited */ false, Z_OBJ_P(ZEND_THIS), index, 2));
} /* }}} */
@@ -653,9 +653,9 @@ PHP_METHOD(ArrayObject, offsetExists)
PHP_METHOD(ArrayObject, offsetGet)
{
zval *value, *index;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &index) == FAILURE) {
- RETURN_THROWS();
- }
+ ZEND_PARSE_PARAMETERS_START(1, 1)
+ Z_PARAM_ZVAL(index)
+ ZEND_PARSE_PARAMETERS_END();
value = spl_array_read_dimension_ex(0, Z_OBJ_P(ZEND_THIS), index, BP_VAR_R, return_value);
if (value != return_value) {
RETURN_COPY_DEREF(value);
@@ -666,9 +666,10 @@ PHP_METHOD(ArrayObject, offsetGet)
PHP_METHOD(ArrayObject, offsetSet)
{
zval *index, *value;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &index, &value) == FAILURE) {
- RETURN_THROWS();
- }
+ ZEND_PARSE_PARAMETERS_START(2, 2)
+ Z_PARAM_ZVAL(index)
+ Z_PARAM_ZVAL(value)
+ ZEND_PARSE_PARAMETERS_END();
spl_array_write_dimension_ex(0, Z_OBJ_P(ZEND_THIS), index, value);
} /* }}} */
@@ -689,9 +690,9 @@ PHP_METHOD(ArrayObject, append)
{
zval *value;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &value) == FAILURE) {
- RETURN_THROWS();
- }
+ ZEND_PARSE_PARAMETERS_START(1, 1)
+ Z_PARAM_ZVAL(value)
+ ZEND_PARSE_PARAMETERS_END();
spl_array_iterator_append(ZEND_THIS, value);
} /* }}} */
@@ -699,9 +700,9 @@ PHP_METHOD(ArrayObject, append)
PHP_METHOD(ArrayObject, offsetUnset)
{
zval *index;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &index) == FAILURE) {
- RETURN_THROWS();
- }
+ ZEND_PARSE_PARAMETERS_START(1, 1)
+ Z_PARAM_ZVAL(index)
+ ZEND_PARSE_PARAMETERS_END();
spl_array_unset_dimension_ex(0, Z_OBJ_P(ZEND_THIS), index);
} /* }}} */
@@ -1000,9 +1001,12 @@ PHP_METHOD(ArrayObject, __construct)
return; /* nothing to do */
}
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "|AlC", &array, &ar_flags, &ce_get_iterator) == FAILURE) {
- RETURN_THROWS();
- }
+ ZEND_PARSE_PARAMETERS_START(0, 3)
+ Z_PARAM_OPTIONAL
+ Z_PARAM_ARRAY_OR_OBJECT(array)
+ Z_PARAM_LONG(ar_flags)
+ Z_PARAM_CLASS(ce_get_iterator)
+ ZEND_PARSE_PARAMETERS_END();
intern = Z_SPLARRAY_P(object);
@@ -1669,9 +1673,11 @@ PHP_METHOD(ArrayIterator, __construct)
return; /* nothing to do */
}
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "|Al", &array, &ar_flags) == FAILURE) {
- RETURN_THROWS();
- }
+ ZEND_PARSE_PARAMETERS_START(0, 2)
+ Z_PARAM_OPTIONAL
+ Z_PARAM_ARRAY_OR_OBJECT(array)
+ Z_PARAM_LONG(ar_flags)
+ ZEND_PARSE_PARAMETERS_END();
intern = Z_SPLARRAY_P(object);