diff --git a/ext/standard/array.c b/ext/standard/array.c index d1f302994fe57..c7f25e10ca728 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -4166,15 +4166,18 @@ PHP_FUNCTION(array_reduce) } /* }}} */ -/* {{{ proto array array_filter(array input [, mixed callback]) +/* {{{ proto array array_filter(array input [, mixed callback, bool pass_key]) Filters elements from the array via the callback. */ PHP_FUNCTION(array_filter) { zval *array; zval **operand; - zval **args[1]; + zval *key; + zval **args[2]; zval *retval = NULL; + zend_bool pass_key = 0; zend_bool have_callback = 0; + int key_type; char *string_key; zend_fcall_info fci = empty_fcall_info; zend_fcall_info_cache fci_cache = empty_fcall_info_cache; @@ -4182,7 +4185,7 @@ PHP_FUNCTION(array_filter) ulong num_key; HashPosition pos; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|f", &array, &fci, &fci_cache) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|fb", &array, &fci, &fci_cache, &pass_key) == FAILURE) { return; } @@ -4195,18 +4198,46 @@ PHP_FUNCTION(array_filter) have_callback = 1; fci.no_separation = 0; fci.retval_ptr_ptr = &retval; - fci.param_count = 1; + + if (pass_key) { + fci.param_count = 2; + } else { + fci.param_count = 1; + } } for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(array), &pos); zend_hash_get_current_data_ex(Z_ARRVAL_P(array), (void **)&operand, &pos) == SUCCESS; zend_hash_move_forward_ex(Z_ARRVAL_P(array), &pos) ) { + key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(array), &string_key, &string_key_len, &num_key, 0, &pos); if (have_callback) { args[0] = operand; + + if (pass_key) { + ALLOC_INIT_ZVAL(key); + switch (key_type) { + case HASH_KEY_IS_STRING: + if (string_key_len > 1) { // protect against null keys + ZVAL_STRINGL(key, string_key, string_key_len - 1, 0); + } + break; + + case HASH_KEY_IS_LONG: + ZVAL_LONG(key, num_key); + break; + } + + args[1] = &key; + } + fci.params = args; if (zend_call_function(&fci, &fci_cache TSRMLS_CC) == SUCCESS && retval) { + if (key) { + zval_ptr_dtor(&key); + } + if (!zend_is_true(retval)) { zval_ptr_dtor(&retval); continue; @@ -4222,7 +4253,7 @@ PHP_FUNCTION(array_filter) } zval_add_ref(operand); - switch (zend_hash_get_current_key_ex(Z_ARRVAL_P(array), &string_key, &string_key_len, &num_key, 0, &pos)) { + switch (key_type) { case HASH_KEY_IS_STRING: zend_hash_update(Z_ARRVAL_P(return_value), string_key, string_key_len, operand, sizeof(zval *), NULL); break; diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index 528e4f65b96e6..7a0accd3c528a 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -589,6 +589,7 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_array_filter, 0, 0, 1) ZEND_ARG_INFO(0, arg) /* ARRAY_INFO(0, arg, 0) */ ZEND_ARG_INFO(0, callback) + ZEND_ARG_INFO(0, pass_key) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_array_map, 0, 0, 2) diff --git a/ext/standard/tests/array/array_filter_error.phpt b/ext/standard/tests/array/array_filter_error.phpt index 20e89aa4b776e..2ba8cc9bc7f7b 100644 --- a/ext/standard/tests/array/array_filter_error.phpt +++ b/ext/standard/tests/array/array_filter_error.phpt @@ -28,7 +28,7 @@ $extra_arg = 10; // with one more than the expected number of arguments echo "-- Testing array_filter() function with more than expected no. of arguments --"; -var_dump( array_filter($input, "odd", $extra_arg) ); +var_dump( array_filter($input, "odd", false, $extra_arg) ); // with incorrect callback function echo "-- Testing array_filter() function with incorrect callback --"; @@ -42,7 +42,7 @@ echo "Done" Warning: array_filter() expects at least 1 parameter, 0 given in %s on line %d NULL -- Testing array_filter() function with more than expected no. of arguments -- -Warning: array_filter() expects at most 2 parameters, 3 given in %s on line %d +Warning: array_filter() expects at most 3 parameters, 4 given in %s on line %d NULL -- Testing array_filter() function with incorrect callback -- Warning: array_filter() expects parameter 2 to be a valid callback, function 'even' not found or invalid function name in %s on line %d diff --git a/ext/standard/tests/array/array_filter_key.phpt b/ext/standard/tests/array/array_filter_key.phpt new file mode 100644 index 0000000000000..8e41c4a2a30d9 --- /dev/null +++ b/ext/standard/tests/array/array_filter_key.phpt @@ -0,0 +1,162 @@ +--TEST-- +Test array_filter() function : key functionality +--FILE-- + 'one', 'zero' => 0, -2 => "value"), //associative array + array("one" => 1, null => 'null', 5.2 => "float", true => 1, "" => 'empty'), // associative array with different keys + array(1 => 'one', 2, "key" => 'value') // combinition of associative and non-associative array +); + +// loop through each element of 'input' with default callback +for($count = 0; $count < count($input_values); $count++) +{ + echo "-- Iteration ".($count + 1). " --\n"; + var_dump( array_filter($input_values[$count], 'vd', true) ); + var_dump( array_filter($input_values[$count], 'vd_key', true) ); +} + +echo "Done"; +?> +--EXPECTF-- +*** Testing array_filter() : key functionality *** +-- Iteration 1 -- +int(0) +int(1) +int(2) +int(3) +array(4) { + [0]=> + int(0) + [1]=> + int(1) + [2]=> + int(2) + [3]=> + int(3) +} +int(0) +int(0) +int(1) +int(1) +int(2) +int(2) +int(3) +int(3) +array(4) { + [0]=> + int(0) + [1]=> + int(1) + [2]=> + int(2) + [3]=> + int(3) +} +-- Iteration 2 -- +string(3) "one" +int(0) +string(5) "value" +array(3) { + [1]=> + string(3) "one" + ["zero"]=> + int(0) + [-2]=> + string(5) "value" +} +string(3) "one" +int(1) +int(0) +string(4) "zero" +string(5) "value" +int(-2) +array(3) { + [1]=> + string(3) "one" + ["zero"]=> + int(0) + [-2]=> + string(5) "value" +} +-- Iteration 3 -- +int(1) +string(5) "empty" +string(5) "float" +int(1) +array(4) { + ["one"]=> + int(1) + [""]=> + string(5) "empty" + [5]=> + string(5) "float" + [1]=> + int(1) +} +int(1) +string(3) "one" +string(5) "empty" +NULL +string(5) "float" +int(5) +int(1) +int(1) +array(4) { + ["one"]=> + int(1) + [""]=> + string(5) "empty" + [5]=> + string(5) "float" + [1]=> + int(1) +} +-- Iteration 4 -- +string(3) "one" +int(2) +string(5) "value" +array(3) { + [1]=> + string(3) "one" + [2]=> + int(2) + ["key"]=> + string(5) "value" +} +string(3) "one" +int(1) +int(2) +int(2) +string(5) "value" +string(3) "key" +array(3) { + [1]=> + string(3) "one" + [2]=> + int(2) + ["key"]=> + string(5) "value" +} +Done