From 5bc2854b37778d7f402db8bb9be9fe33df64258e Mon Sep 17 00:00:00 2001 From: Ben Ramsey Date: Fri, 11 Jan 2013 16:57:11 -0600 Subject: [PATCH] array_column: Implement ability to specify an index column --- ext/standard/array.c | 97 +++++++++++--- ext/standard/basic_functions.c | 3 +- .../tests/array/array_column_basic.phpt | 123 +++++++++++++++++- .../tests/array/array_column_error.phpt | 56 +++++--- 4 files changed, 235 insertions(+), 44 deletions(-) diff --git a/ext/standard/array.c b/ext/standard/array.c index 91a8833347..fa19737522 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -2563,42 +2563,66 @@ PHP_FUNCTION(array_count_values) } /* }}} */ -/* {{{ proto array array_column(array input, mixed key) - Return the values from a single column in the input array, identified by the key */ +/* {{{ proto array array_column(array input, mixed column_key[, mixed index_key]) + Return the values from a single column in the input array, identified by the + value_key and optionally indexed by the index_key */ PHP_FUNCTION(array_column) { - zval *zarray, *zoffset, **data, **zvalue; + zval *zarray, *zcolumn, *zkey = NULL, **data, **zcolval, **zkeyval; HashTable *arr_hash; HashPosition pointer; - long index = 0; - char *key = NULL; - int key_len = 0; + ulong column_idx = 0, key_idx = 0, keyval_idx = 0; + char *column = NULL, *key = NULL, *keyval = NULL; + int column_len = 0, key_len = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "az", &zarray, &zoffset) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "az|z", &zarray, &zcolumn, &zkey) == FAILURE) { return; } - switch (Z_TYPE_P(zoffset)) { + switch (Z_TYPE_P(zcolumn)) { case IS_NULL: - index = 0; + column_idx = 0; break; case IS_LONG: - index = Z_LVAL_P(zoffset); + column_idx = Z_LVAL_P(zcolumn); break; case IS_STRING: - key = Z_STRVAL_P(zoffset); - key_len = Z_STRLEN_P(zoffset); + column = Z_STRVAL_P(zcolumn); + column_len = Z_STRLEN_P(zcolumn); break; case IS_OBJECT: - convert_to_string(zoffset); - key = Z_STRVAL_P(zoffset); - key_len = Z_STRLEN_P(zoffset); + convert_to_string(zcolumn); + column = Z_STRVAL_P(zcolumn); + column_len = Z_STRLEN_P(zcolumn); break; default: - php_error_docref(NULL TSRMLS_CC, E_WARNING, "The key should be either a string or an integer"); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "The column key should be either a string or an integer"); RETURN_FALSE; } + if (zkey) { + switch (Z_TYPE_P(zkey)) { + case IS_NULL: + key_idx = 0; + break; + case IS_LONG: + key_idx = Z_LVAL_P(zkey); + break; + case IS_STRING: + key = Z_STRVAL_P(zkey); + key_len = Z_STRLEN_P(zkey); + break; + case IS_OBJECT: + convert_to_string(zkey); + key = Z_STRVAL_P(zkey); + key_len = Z_STRLEN_P(zkey); + break; + default: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "The index key should be either a string or an integer"); + RETURN_FALSE; + } + } + arr_hash = Z_ARRVAL_P(zarray); array_init(return_value); @@ -2607,14 +2631,47 @@ PHP_FUNCTION(array_column) zend_hash_move_forward_ex(arr_hash, &pointer)) { if (Z_TYPE_PP(data) == IS_ARRAY) { - if (key && zend_hash_find(Z_ARRVAL_PP(data), key, key_len + 1, (void**)&zvalue) == FAILURE) { + if (column && zend_hash_find(Z_ARRVAL_PP(data), column, column_len + 1, (void**)&zcolval) == FAILURE) { continue; - } else if (!key && zend_hash_index_find(Z_ARRVAL_PP(data), index, (void**)&zvalue) == FAILURE) { + } else if (!column && zend_hash_index_find(Z_ARRVAL_PP(data), column_idx, (void**)&zcolval) == FAILURE) { continue; } - Z_ADDREF_PP(zvalue); - add_next_index_zval(return_value, *zvalue); + Z_ADDREF_PP(zcolval); + + keyval = NULL; + keyval_idx = NULL; + + if (zkey) { + if (key && zend_hash_find(Z_ARRVAL_PP(data), key, key_len + 1, (void**)&zkeyval) == FAILURE) { + keyval_idx = NULL; + } else if (!key && zend_hash_index_find(Z_ARRVAL_PP(data), key_idx, (void**)&zkeyval) == FAILURE) { + keyval_idx = NULL; + } else { + switch (Z_TYPE_PP(zkeyval)) { + case IS_LONG: + keyval_idx = Z_LVAL_PP(zkeyval); + break; + case IS_STRING: + keyval = Z_STRVAL_PP(zkeyval); + break; + case IS_OBJECT: + convert_to_string(*zkeyval); + keyval = Z_STRVAL_PP(zkeyval); + break; + default: + keyval_idx = NULL; + } + } + } + + if (keyval) { + add_assoc_zval(return_value, keyval, *zcolval); + } else if (keyval_idx != NULL) { + add_index_zval(return_value, keyval_idx, *zcolval); + } else { + add_next_index_zval(return_value, *zcolval); + } } } diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index 2e44150871..5e123528c3 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -435,7 +435,8 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_array_column, 0, 0, 2) ZEND_ARG_INFO(0, arg) /* ARRAY_INFO(0, arg, 0) */ - ZEND_ARG_INFO(0, key) + ZEND_ARG_INFO(0, column_key) + ZEND_ARG_INFO(0, index_key) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_array_reverse, 0, 0, 1) diff --git a/ext/standard/tests/array/array_column_basic.phpt b/ext/standard/tests/array/array_column_basic.phpt index fa8fe2fb5a..70ce2136b4 100644 --- a/ext/standard/tests/array/array_column_basic.phpt +++ b/ext/standard/tests/array/array_column_basic.phpt @@ -3,7 +3,7 @@ Test array_column() function: basic functionality --FILE-- 'foo', 'b' => 'bar'), - array('a' => 'baz', 'c' => 'qux'), + array('a' => 'foo', 'b' => 'bar', 'e' => 'bbb'), + array('a' => 'baz', 'c' => 'qux', 'd' => 'aaa'), + array('a' => 'eee', 'b' => 'fff', 'e' => 'ggg'), ); var_dump(array_column($mismatchedColumns, 'c')); +var_dump(array_column($mismatchedColumns, 'c', 'a')); +var_dump(array_column($mismatchedColumns, 'a', 'd')); +var_dump(array_column($mismatchedColumns, 'a', 'e')); +var_dump(array_column($mismatchedColumns, 'b')); +var_dump(array_column($mismatchedColumns, 'b', 'a')); echo "\n*** Testing use of object converted to string ***\n"; class Foo @@ -105,8 +120,17 @@ class Foo return 'last_name'; } } +class Bar +{ + public function __toString() + { + return 'first_name'; + } +} $f = new Foo(); +$b = new Bar(); var_dump(array_column($records, $f)); +var_dump(array_column($records, $f, $b)); echo "Done\n"; ?> @@ -130,6 +154,24 @@ array(3) { [2]=> int(3) } +-- last_name column from recordset, keyed by value from id column -- +array(3) { + [1]=> + string(3) "Doe" + [2]=> + string(5) "Smith" + [3]=> + string(5) "Jones" +} +-- last_name column from recordset, keyed by value from first_name column -- +array(3) { + ["John"]=> + string(3) "Doe" + ["Sally"]=> + string(5) "Smith" + ["Jane"]=> + string(5) "Jones" +} *** Testing multiple data types *** array(8) { @@ -151,6 +193,25 @@ array(8) { [7]=> resource(5) of type (stream) } +array(8) { + [1]=> + object(stdClass)#1 (0) { + } + [2]=> + float(34.2345) + [3]=> + bool(true) + [4]=> + bool(false) + [5]=> + NULL + [6]=> + int(1234) + [7]=> + string(3) "Foo" + [8]=> + resource(5) of type (stream) +} *** Testing numeric column keys *** array(3) { @@ -161,12 +222,28 @@ array(3) { [2]=> string(3) "333" } +array(3) { + ["aaa"]=> + string(3) "111" + ["bbb"]=> + string(3) "222" + ["ccc"]=> + string(3) "333" +} *** Testing failure to find specified column *** array(0) { } array(0) { } +array(3) { + [0]=> + string(3) "aaa" + [1]=> + string(3) "bbb" + [2]=> + string(3) "ccc" +} *** Testing single dimensional array *** array(0) { @@ -177,6 +254,38 @@ array(1) { [0]=> string(3) "qux" } +array(1) { + ["baz"]=> + string(3) "qux" +} +array(3) { + [0]=> + string(3) "foo" + ["aaa"]=> + string(3) "baz" + [1]=> + string(3) "eee" +} +array(3) { + ["bbb"]=> + string(3) "foo" + [0]=> + string(3) "baz" + ["ggg"]=> + string(3) "eee" +} +array(2) { + [0]=> + string(3) "bar" + [1]=> + string(3) "fff" +} +array(2) { + ["foo"]=> + string(3) "bar" + ["eee"]=> + string(3) "fff" +} *** Testing use of object converted to string *** array(3) { @@ -187,4 +296,12 @@ array(3) { [2]=> string(5) "Jones" } +array(3) { + ["John"]=> + string(3) "Doe" + ["Sally"]=> + string(5) "Smith" + ["Jane"]=> + string(5) "Jones" +} Done diff --git a/ext/standard/tests/array/array_column_error.phpt b/ext/standard/tests/array/array_column_error.phpt index d409d3b12e..1aec1acc63 100644 --- a/ext/standard/tests/array/array_column_error.phpt +++ b/ext/standard/tests/array/array_column_error.phpt @@ -3,7 +3,7 @@ Test array_column() function: error conditions --FILE-- --EXPECTF-- @@ -42,17 +48,12 @@ echo "Done\n"; -- Testing array_column() function with Zero arguments -- -Warning: array_column() expects exactly 2 parameters, 0 given in %s on line %d +Warning: array_column() expects at least 2 parameters, 0 given in %s on line %d NULL -- Testing array_column() function with One argument -- -Warning: array_column() expects exactly 2 parameters, 1 given in %s on line %d -NULL - --- Testing array_column() function with more than expected no. of arguments -- - -Warning: array_column() expects exactly 2 parameters, 3 given in %s on line %d +Warning: array_column() expects at least 2 parameters, 1 given in %s on line %d NULL -- Testing array_column() function with string as first parameter -- @@ -65,18 +66,33 @@ NULL Warning: array_column() expects parameter 1 to be array, integer given in %s on line %d NULL --- Testing array_column() key parameter should be a string or an integer (testing bool) -- +-- Testing array_column() column key parameter should be a string or an integer (testing bool) -- + +Warning: array_column(): The column key should be either a string or an integer in %s on line %d +bool(false) + +-- Testing array_column() column key parameter should be a string or integer (testing float) -- + +Warning: array_column(): The column key should be either a string or an integer in %s on line %d +bool(false) + +-- Testing array_column() column key parameter should be a string or integer (testing array) -- + +Warning: array_column(): The column key should be either a string or an integer in %s on line %d +bool(false) + +-- Testing array_column() index key parameter should be a string or an integer (testing bool) -- -Warning: array_column(): The key should be either a string or an integer in %s on line %d +Warning: array_column(): The index key should be either a string or an integer in %s on line %d bool(false) --- Testing array_column() key parameter should be a string or integer (testing float) -- +-- Testing array_column() index key parameter should be a string or integer (testing float) -- -Warning: array_column(): The key should be either a string or an integer in %s on line %d +Warning: array_column(): The index key should be either a string or an integer in %s on line %d bool(false) --- Testing array_column() key parameter should be a string or integer (testing array) -- +-- Testing array_column() index key parameter should be a string or integer (testing array) -- -Warning: array_column(): The key should be either a string or an integer in %s on line %d +Warning: array_column(): The index key should be either a string or an integer in %s on line %d bool(false) Done -- 2.40.0