From 117f876a78367bc7c62e8e0699c06b2090769402 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 5 Mar 2026 12:15:21 +0000 Subject: [PATCH 1/2] ext/spl: ArrayObject improve ZPP test for usort() methods --- .../arrayObject_uasort_error1.phpt | 20 +++++-------------- .../arrayObject_uksort_error1.phpt | 20 +++++-------------- 2 files changed, 10 insertions(+), 30 deletions(-) diff --git a/ext/spl/tests/ArrayObject/arrayObject_uasort_error1.phpt b/ext/spl/tests/ArrayObject/arrayObject_uasort_error1.phpt index d4c8532451277..32defd35e6fc0 100644 --- a/ext/spl/tests/ArrayObject/arrayObject_uasort_error1.phpt +++ b/ext/spl/tests/ArrayObject/arrayObject_uasort_error1.phpt @@ -1,26 +1,16 @@ --TEST-- -Test ArrayObject::uasort() function : wrong arg count +ArrayObject::uasort() function: non callable error --FILE-- uasort(); -} catch (ArgumentCountError $e) { - echo $e->getMessage() . "\n"; + $ao->uasort('not_a_valid_function'); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; } -try { - $ao->uasort(1,2); -} catch (ArgumentCountError $e) { - echo $e->getMessage() . "\n"; -} ?> --EXPECT-- -ArrayObject::uasort() expects exactly 1 argument, 0 given -ArrayObject::uasort() expects exactly 1 argument, 2 given +TypeError: uasort(): Argument #2 ($callback) must be a valid callback, function "not_a_valid_function" not found or invalid function name diff --git a/ext/spl/tests/ArrayObject/arrayObject_uksort_error1.phpt b/ext/spl/tests/ArrayObject/arrayObject_uksort_error1.phpt index 71164383e41bd..11b40aae8c8fb 100644 --- a/ext/spl/tests/ArrayObject/arrayObject_uksort_error1.phpt +++ b/ext/spl/tests/ArrayObject/arrayObject_uksort_error1.phpt @@ -1,26 +1,16 @@ --TEST-- -Test ArrayObject::uksort() function : wrong arg count +ArrayObject::uksort() function: non callable error --FILE-- uksort(); -} catch (ArgumentCountError $e) { - echo $e->getMessage() . "\n"; + $ao->uksort('not_a_valid_function'); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; } -try { - $ao->uksort(1,2); -} catch (ArgumentCountError $e) { - echo $e->getMessage() . "\n"; -} ?> --EXPECT-- -ArrayObject::uksort() expects exactly 1 argument, 0 given -ArrayObject::uksort() expects exactly 1 argument, 2 given +TypeError: uksort(): Argument #2 ($callback) must be a valid callback, function "not_a_valid_function" not found or invalid function name From 6a983ef717b3bec6f7639038161ffc1bce6e786f Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 5 Mar 2026 12:42:20 +0000 Subject: [PATCH 2/2] ext/spl/ArrayObject: handle ZPP for each sort methods directly --- ext/spl/spl_array.c | 125 ++++++++++++++++++++++++-------------------- 1 file changed, 68 insertions(+), 57 deletions(-) diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c index 3d6870a7ee953..93b0f7256ed0a 100644 --- a/ext/spl/spl_array.c +++ b/ext/spl/spl_array.c @@ -1200,18 +1200,12 @@ PHP_METHOD(ArrayObject, count) RETURN_LONG(spl_array_object_count_elements_helper(intern)); } /* }}} */ -enum spl_array_object_sort_methods { - SPL_NAT_SORT, - SPL_CALLBACK_SORT, - SPL_OPTIONAL_FLAG_SORT -}; - -static void spl_array_method(INTERNAL_FUNCTION_PARAMETERS, const char *fname, size_t fname_len, enum spl_array_object_sort_methods use_arg) /* {{{ */ +static void spl_array_method(zval *return_value, spl_array_object *intern, const char *fname, size_t fname_len, const zval *extra_arg) /* {{{ */ { - spl_array_object *intern = Z_SPLARRAY_P(ZEND_THIS); HashTable **ht_ptr = spl_array_get_hash_table_ptr(intern); HashTable *aht = *ht_ptr; - zval params[2], *arg = NULL; + zval params[2]; + uint32_t param_num = 1; zend_function *fn = zend_hash_str_find_ptr(EG(function_table), fname, fname_len); if (UNEXPECTED(fn == NULL)) { @@ -1223,68 +1217,85 @@ static void spl_array_method(INTERNAL_FUNCTION_PARAMETERS, const char *fname, si ZVAL_ARR(Z_REFVAL(params[0]), aht); GC_ADDREF(aht); - if (use_arg == SPL_NAT_SORT) { - if (zend_parse_parameters_none() == FAILURE) { - goto exit; - } - - intern->nApplyCount++; - zend_call_known_function(fn, NULL, NULL, return_value, 1, params, NULL); - intern->nApplyCount--; - } else if (use_arg == SPL_OPTIONAL_FLAG_SORT) { - zend_long sort_flags = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &sort_flags) == FAILURE) { - goto exit; - } - ZVAL_LONG(¶ms[1], sort_flags); - intern->nApplyCount++; - zend_call_known_function(fn, NULL, NULL, return_value, 2, params, NULL); - intern->nApplyCount--; - } else { - ZEND_ASSERT(use_arg == SPL_CALLBACK_SORT); - if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &arg) == FAILURE) { - goto exit; - } - ZVAL_COPY_VALUE(¶ms[1], arg); - intern->nApplyCount++; - zend_call_known_function(fn, NULL, NULL, return_value, 2, params, NULL); - intern->nApplyCount--; + if (extra_arg) { + param_num = 2; + ZVAL_COPY_VALUE(¶ms[1], extra_arg); } + intern->nApplyCount++; + zend_call_known_function(fn, NULL, NULL, return_value, param_num, params, NULL); + intern->nApplyCount--; -exit: - { - zval *ht_zv = Z_REFVAL(params[0]); - zend_array_release(*ht_ptr); - SEPARATE_ARRAY(ht_zv); - *ht_ptr = Z_ARRVAL_P(ht_zv); - ZVAL_NULL(ht_zv); - zval_ptr_dtor(¶ms[0]); - } + zval *ht_zv = Z_REFVAL(params[0]); + zend_array_release(*ht_ptr); + SEPARATE_ARRAY(ht_zv); + *ht_ptr = Z_ARRVAL_P(ht_zv); + ZVAL_NULL(ht_zv); + zval_ptr_dtor(¶ms[0]); } /* }}} */ -#define SPL_ARRAY_METHOD(cname, fname, use_arg) \ -PHP_METHOD(cname, fname) \ -{ \ - spl_array_method(INTERNAL_FUNCTION_PARAM_PASSTHRU, #fname, sizeof(#fname)-1, use_arg); \ -} - /* Sort the entries by values. */ -SPL_ARRAY_METHOD(ArrayObject, asort, SPL_OPTIONAL_FLAG_SORT) +PHP_METHOD(ArrayObject, asort) +{ + zend_long sort_flags = 0; + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &sort_flags) == FAILURE) { + RETURN_THROWS(); + } + zval sort_flag_param; + ZVAL_LONG(&sort_flag_param, sort_flags); + + spl_array_method(return_value, Z_SPLARRAY_P(ZEND_THIS), ZEND_STRL("asort"), &sort_flag_param); +} /* Sort the entries by key. */ -SPL_ARRAY_METHOD(ArrayObject, ksort, SPL_OPTIONAL_FLAG_SORT) +PHP_METHOD(ArrayObject, ksort) +{ + zend_long sort_flags = 0; + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &sort_flags) == FAILURE) { + RETURN_THROWS(); + } + zval sort_flag_param; + ZVAL_LONG(&sort_flag_param, sort_flags); + + spl_array_method(return_value, Z_SPLARRAY_P(ZEND_THIS), ZEND_STRL("ksort"), &sort_flag_param); +} /* Sort the entries by values user defined function. */ -SPL_ARRAY_METHOD(ArrayObject, uasort, SPL_CALLBACK_SORT) +PHP_METHOD(ArrayObject, uasort) +{ + zval *callback = NULL; + /* TODO: Should check variable is callable */ + if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &callback) == FAILURE) { + RETURN_THROWS(); + } + spl_array_method(return_value, Z_SPLARRAY_P(ZEND_THIS), ZEND_STRL("uasort"), callback); +} /* Sort the entries by key using user defined function. */ -SPL_ARRAY_METHOD(ArrayObject, uksort, SPL_CALLBACK_SORT) +PHP_METHOD(ArrayObject, uksort) +{ + zval *callback = NULL; + /* TODO: Should check variable is callable */ + if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &callback) == FAILURE) { + RETURN_THROWS(); + } + spl_array_method(return_value, Z_SPLARRAY_P(ZEND_THIS), ZEND_STRL("uksort"), callback); +} /* Sort the entries by values using "natural order" algorithm. */ -SPL_ARRAY_METHOD(ArrayObject, natsort, SPL_NAT_SORT) +PHP_METHOD(ArrayObject, natsort) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + spl_array_method(return_value, Z_SPLARRAY_P(ZEND_THIS), ZEND_STRL("natsort"), NULL); +} -/* {{{ Sort the entries by key using case-insensitive "natural order" algorithm. */ -SPL_ARRAY_METHOD(ArrayObject, natcasesort, SPL_NAT_SORT) +/* Sort the entries by key using case-insensitive "natural order" algorithm. */ +PHP_METHOD(ArrayObject, natcasesort) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + spl_array_method(return_value, Z_SPLARRAY_P(ZEND_THIS), ZEND_STRL("natcasesort"), NULL); +} /* {{{ Serialize the object */ PHP_METHOD(ArrayObject, serialize)