summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authorSherif Ramadan <googleguy@php.net>2013-10-30 09:36:19 -0400
committerSherif Ramadan <googleguy@php.net>2013-10-30 09:36:19 -0400
commit98c9e56ef0be89953729754bd9949e14c7248c15 (patch)
tree53f3c02afd4338b05d7d03f83cdb69953e2b07d5 /ext
parent4218e89f8df4ca3897e3aad595e0c2c9cf4c3aca (diff)
parent75ba75e2055d670e204e6361732995ba27b05896 (diff)
downloadphp-git-98c9e56ef0be89953729754bd9949e14c7248c15.tar.gz
Merge branch 'pull-request/287'
Add ability to use array keys with array_filter(). This adds a third (optional) argument to array_filter() that will determine what gets passed to the callback, the array key, value or both. The third argument can be one of two constants: ARRAY_FILTER_USE_BOTH or, ARRAY_FILTER_USE_KEY.
Diffstat (limited to 'ext')
-rw-r--r--ext/standard/array.c54
-rw-r--r--ext/standard/basic_functions.c1
-rw-r--r--ext/standard/php_array.h3
-rw-r--r--ext/standard/tests/array/array_filter_error.phpt4
-rw-r--r--ext/standard/tests/array/array_filter_variation10.phpt103
5 files changed, 154 insertions, 11 deletions
diff --git a/ext/standard/array.c b/ext/standard/array.c
index 411e8de9ec..17be59d6ca 100644
--- a/ext/standard/array.c
+++ b/ext/standard/array.c
@@ -127,6 +127,9 @@ PHP_MINIT_FUNCTION(array) /* {{{ */
REGISTER_LONG_CONSTANT("COUNT_NORMAL", COUNT_NORMAL, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("COUNT_RECURSIVE", COUNT_RECURSIVE, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("ARRAY_FILTER_USE_BOTH", ARRAY_FILTER_USE_BOTH, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("ARRAY_FILTER_USE_KEY", ARRAY_FILTER_USE_KEY, CONST_CS | CONST_PERSISTENT);
+
return SUCCESS;
}
/* }}} */
@@ -4205,9 +4208,11 @@ PHP_FUNCTION(array_filter)
{
zval *array;
zval **operand;
- zval **args[1];
+ zval **args[2];
zval *retval = NULL;
+ zval *key = NULL;
zend_bool have_callback = 0;
+ long use_type = 0;
char *string_key;
zend_fcall_info fci = empty_fcall_info;
zend_fcall_info_cache fci_cache = empty_fcall_info_cache;
@@ -4215,7 +4220,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|fl", &array, &fci, &fci_cache, &use_type) == FAILURE) {
return;
}
@@ -4228,23 +4233,54 @@ PHP_FUNCTION(array_filter)
have_callback = 1;
fci.no_separation = 0;
fci.retval_ptr_ptr = &retval;
- fci.param_count = 1;
+
+ if (use_type == ARRAY_FILTER_USE_BOTH) {
+ fci.param_count = 2;
+ args[1] = &key;
+ } else {
+ fci.param_count = 1;
+ if (use_type == ARRAY_FILTER_USE_KEY) {
+ args[0] = &key;
+ }
+ }
}
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)
) {
+ int 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 (use_type) {
+ MAKE_STD_ZVAL(key);
+ /* Set up the key */
+ switch (key_type) {
+ case HASH_KEY_IS_LONG:
+ Z_TYPE_P(key) = IS_LONG;
+ Z_LVAL_P(key) = num_key;
+ break;
+
+ case HASH_KEY_IS_STRING:
+ ZVAL_STRINGL(key, string_key, string_key_len - 1, 1);
+ break;
+ }
+ }
+
+ if (use_type != ARRAY_FILTER_USE_KEY) {
+ args[0] = operand;
+ }
fci.params = args;
if (zend_call_function(&fci, &fci_cache TSRMLS_CC) == SUCCESS && retval) {
- if (!zend_is_true(retval)) {
- zval_ptr_dtor(&retval);
+ int retval_true = zend_is_true(retval);
+
+ zval_ptr_dtor(&retval);
+ if (use_type) {
+ zval_ptr_dtor(&key);
+ }
+ if (!retval_true) {
continue;
- } else {
- zval_ptr_dtor(&retval);
}
} else {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "An error occurred while invoking the filter callback");
@@ -4255,7 +4291,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 5ce0d3c126..cb1ada22e2 100644
--- a/ext/standard/basic_functions.c
+++ b/ext/standard/basic_functions.c
@@ -596,6 +596,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, use_keys)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_array_map, 0, 0, 2)
diff --git a/ext/standard/php_array.h b/ext/standard/php_array.h
index 1cf2779071..ef43cddfcc 100644
--- a/ext/standard/php_array.h
+++ b/ext/standard/php_array.h
@@ -117,6 +117,9 @@ PHPAPI int php_multisort_compare(const void *a, const void *b TSRMLS_DC);
#define PHP_SORT_NATURAL 6
#define PHP_SORT_FLAG_CASE 8
+#define ARRAY_FILTER_USE_BOTH 1
+#define ARRAY_FILTER_USE_KEY 2
+
ZEND_BEGIN_MODULE_GLOBALS(array)
int *multisort_flags[2];
int (*compare_func)(zval *result, zval *op1, zval *op2 TSRMLS_DC);
diff --git a/ext/standard/tests/array/array_filter_error.phpt b/ext/standard/tests/array/array_filter_error.phpt
index 20e89aa4b7..3f8f51bc14 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", $extra_arg, $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_variation10.phpt b/ext/standard/tests/array/array_filter_variation10.phpt
new file mode 100644
index 0000000000..f0a6115f79
--- /dev/null
+++ b/ext/standard/tests/array/array_filter_variation10.phpt
@@ -0,0 +1,103 @@
+--TEST--
+Test array_filter() function : usage variations - using the array keys inside 'callback'
+--FILE--
+<?php
+/* Prototype : array array_filter(array $input [, callback $callback [, bool $use_type = ARRAY_FILTER_USE_VALUE]])
+ * Description: Filters elements from the array via the callback.
+ * Source code: ext/standard/array.c
+*/
+
+/*
+* Using array keys as an argument to the 'callback'
+*/
+
+echo "*** Testing array_filter() : usage variations - using array keys in 'callback' ***\n";
+
+$input = array(0, 1, -1, 10, 100, 1000, 'Hello', null);
+$small = array(123);
+
+function dump($value, $key)
+{
+ echo "$key = $value\n";
+}
+
+var_dump( array_filter($input, 'dump', true) );
+
+echo "*** Testing array_filter() : usage variations - 'callback' filters based on key value ***\n";
+
+function dump2($value, $key)
+{
+ return $key > 4;
+}
+
+var_dump( array_filter($input, 'dump2', true) );
+
+echo "*** Testing array_filter() : usage variations - 'callback' expecting second argument ***\n";
+
+var_dump( array_filter($small, 'dump', false) );
+
+echo "*** Testing array_filter() with various use types ***\n";
+
+$mixed = array(1 => 'a', 2 => 'b', 'a' => 1, 'b' => 2);
+
+var_dump(array_filter($mixed, 'is_numeric', ARRAY_FILTER_USE_KEY));
+
+var_dump(array_filter($mixed, 'is_numeric', 0));
+
+var_dump(array_filter($mixed, 'is_numeric', ARRAY_FILTER_USE_BOTH));
+
+echo "Done"
+?>
+--EXPECTF--
+*** Testing array_filter() : usage variations - using array keys in 'callback' ***
+0 = 0
+1 = 1
+2 = -1
+3 = 10
+4 = 100
+5 = 1000
+6 = Hello
+7 =
+array(0) {
+}
+*** Testing array_filter() : usage variations - 'callback' filters based on key value ***
+array(3) {
+ [5]=>
+ int(1000)
+ [6]=>
+ string(5) "Hello"
+ [7]=>
+ NULL
+}
+*** Testing array_filter() : usage variations - 'callback' expecting second argument ***
+
+Warning: Missing argument 2 for dump() in %s on line %d
+
+Notice: Undefined variable: key in %s on line %d
+ = 123
+array(0) {
+}
+*** Testing array_filter() with various use types ***
+array(2) {
+ [1]=>
+ string(1) "a"
+ [2]=>
+ string(1) "b"
+}
+array(2) {
+ ["a"]=>
+ int(1)
+ ["b"]=>
+ int(2)
+}
+
+Warning: is_numeric() expects exactly 1 parameter, 2 given in %s on line 44
+
+Warning: is_numeric() expects exactly 1 parameter, 2 given in %s on line 44
+
+Warning: is_numeric() expects exactly 1 parameter, 2 given in %s on line 44
+
+Warning: is_numeric() expects exactly 1 parameter, 2 given in %s on line 44
+array(0) {
+}
+Done