diff --git a/ext/standard/array.c b/ext/standard/array.c index 4ab3a690120b2..6599df1cd510f 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -6582,6 +6582,83 @@ PHP_FUNCTION(array_filter) } /* }}} */ +/* {{{ Filters elements from the array via the callback. */ +PHP_FUNCTION(list_filter) +{ + zval *array; + zval *operand; + zval *key; + zval args[2]; + zval retval; + bool have_callback = 0; + zend_long use_type = 0; + zend_string *string_key; + zend_fcall_info fci = empty_fcall_info; + zend_fcall_info_cache fci_cache = empty_fcall_info_cache; + zend_ulong num_key; + + ZEND_PARSE_PARAMETERS_START(1, 3) + Z_PARAM_ARRAY(array) + Z_PARAM_OPTIONAL + Z_PARAM_FUNC_OR_NULL(fci, fci_cache) + Z_PARAM_LONG(use_type) + ZEND_PARSE_PARAMETERS_END(); + + if (zend_hash_num_elements(Z_ARRVAL_P(array)) == 0) { + RETVAL_EMPTY_ARRAY(); + return; + } + array_init(return_value); + + if (ZEND_FCI_INITIALIZED(fci)) { + have_callback = 1; + fci.retval = &retval; + if (use_type == ARRAY_FILTER_USE_BOTH) { + fci.param_count = 2; + key = &args[1]; + } else { + fci.param_count = 1; + key = &args[0]; + } + } + + ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_key, string_key, operand) { + if (have_callback) { + if (use_type) { + /* Set up the key */ + if (!string_key) { + ZVAL_LONG(key, num_key); + } else { + ZVAL_STR(key, string_key); + } + } + if (use_type != ARRAY_FILTER_USE_KEY) { + ZVAL_COPY_VALUE(&args[0], operand); + } + fci.params = args; + + zend_result result = zend_call_function(&fci, &fci_cache); + ZEND_ASSERT(result == SUCCESS); + + if (UNEXPECTED(EG(exception))) { + RETURN_THROWS(); + } + + if (!php_is_true(&retval)) { + continue; + } + } else if (!zend_is_true(operand)) { + continue; + } + + zval new_val; + ZVAL_COPY(&new_val, operand); + zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &new_val); + zval_add_ref(operand); + } ZEND_HASH_FOREACH_END(); +} +/* }}} */ + /* {{{ Internal function to find an array element for a user closure. */ enum php_array_find_result { PHP_ARRAY_FIND_EXCEPTION = -1, diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php index e7f4ff8844714..aa6b667610068 100644 --- a/ext/standard/basic_functions.stub.php +++ b/ext/standard/basic_functions.stub.php @@ -1877,6 +1877,8 @@ function array_reduce(array $array, callable $callback, mixed $initial = null): function array_filter(array $array, ?callable $callback = null, int $mode = 0): array {} +function list_filter(array $array, ?callable $callback = null, int $mode = 0): array {} + function array_find(array $array, callable $callback): mixed {} function array_find_key(array $array, callable $callback): mixed {} diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index 3d92288643159..638802e8649cf 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 85677dc3476d25b7820fd3a26fe39f2e9378b6e7 */ + * Stub hash: f2a8b629fe3e2ee7f7d9d8163e6536f811ee8c7c */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0) @@ -336,6 +336,8 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_array_filter, 0, 1, IS_ARRAY, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, mode, IS_LONG, 0, "0") ZEND_END_ARG_INFO() +#define arginfo_list_filter arginfo_array_filter + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_array_find, 0, 2, IS_MIXED, 0) ZEND_ARG_TYPE_INFO(0, array, IS_ARRAY, 0) ZEND_ARG_TYPE_INFO(0, callback, IS_CALLABLE, 0) @@ -2380,6 +2382,7 @@ ZEND_FUNCTION(array_sum); ZEND_FUNCTION(array_product); ZEND_FUNCTION(array_reduce); ZEND_FUNCTION(array_filter); +ZEND_FUNCTION(list_filter); ZEND_FUNCTION(array_find); ZEND_FUNCTION(array_find_key); ZEND_FUNCTION(array_any); @@ -2973,6 +2976,7 @@ static const zend_function_entry ext_functions[] = { ZEND_RAW_FENTRY("array_product", zif_array_product, arginfo_array_product, ZEND_ACC_COMPILE_TIME_EVAL, NULL, NULL) ZEND_FE(array_reduce, arginfo_array_reduce) ZEND_FE(array_filter, arginfo_array_filter) + ZEND_FE(list_filter, arginfo_list_filter) ZEND_FE(array_find, arginfo_array_find) ZEND_FE(array_find_key, arginfo_array_find_key) ZEND_FE(array_any, arginfo_array_any) diff --git a/ext/standard/tests/general_functions/list_array.phpt b/ext/standard/tests/general_functions/list_array.phpt new file mode 100644 index 0000000000000..30775c770e747 --- /dev/null +++ b/ext/standard/tests/general_functions/list_array.phpt @@ -0,0 +1,25 @@ +--TEST-- +Test list_filter() function +--FILE-- + 1, 'b' => 2, 'c' => 3]; + +var_dump(array_is_list($array1)); +var_dump(array_is_list(array_filter($array1))); +var_dump(array_is_list(list_filter($array1))); + + +var_dump(array_is_list($array2)); +var_dump(array_is_list(array_filter($array2))); +var_dump(array_is_list(list_filter($array2))); + +?> +--EXPECT-- +bool(true) +bool(false) +bool(true) +bool(false) +bool(false) +bool(true)