diff --git a/ext/standard/array.c b/ext/standard/array.c index e804ff8fc059a..2057351c085bc 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -2563,6 +2563,64 @@ 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 */ +PHP_FUNCTION(array_column) +{ + zval *zarray, *zoffset, **data, **zvalue; + HashTable *arr_hash; + HashPosition pointer; + long index = 0; + char *key = NULL; + int key_len = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "az", &zarray, &zoffset) == FAILURE) { + return; + } + + switch (Z_TYPE_P(zoffset)) { + case IS_NULL: + index = 0; + break; + case IS_LONG: + index = Z_LVAL_P(zoffset); + break; + case IS_STRING: + key = Z_STRVAL_P(zoffset); + key_len = Z_STRLEN_P(zoffset); + break; + case IS_OBJECT: + convert_to_string(zoffset); + key = Z_STRVAL_P(zoffset); + key_len = Z_STRLEN_P(zoffset); + break; + default: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "The key should be either a string or an integer"); + RETURN_FALSE; + } + + arr_hash = Z_ARRVAL_P(zarray); + array_init(return_value); + + for (zend_hash_internal_pointer_reset_ex(arr_hash, &pointer); + zend_hash_get_current_data_ex(arr_hash, (void**)&data, &pointer) == SUCCESS; + 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) { + continue; + } else if (!key && zend_hash_index_find(Z_ARRVAL_PP(data), index, (void**)&zvalue) == FAILURE) { + continue; + } + + Z_ADDREF_PP(zvalue); + add_next_index_zval(return_value, *zvalue); + } + + } +} +/* }}} */ + /* {{{ proto array array_reverse(array input [, bool preserve keys]) Return input as a new array with the order of the entries reversed */ PHP_FUNCTION(array_reverse) diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index 99831a1f42115..4879a4a20c772 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -433,6 +433,11 @@ ZEND_BEGIN_ARG_INFO(arginfo_array_count_values, 0) ZEND_ARG_INFO(0, arg) /* ARRAY_INFO(0, arg, 0) */ 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_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO_EX(arginfo_array_reverse, 0, 0, 1) ZEND_ARG_INFO(0, input) /* ARRAY_INFO(0, arg, 0) */ ZEND_ARG_INFO(0, preserve_keys) @@ -3299,6 +3304,7 @@ const zend_function_entry basic_functions[] = { /* {{{ */ PHP_FE(array_keys, arginfo_array_keys) PHP_FE(array_values, arginfo_array_values) PHP_FE(array_count_values, arginfo_array_count_values) + PHP_FE(array_column, arginfo_array_column) PHP_FE(array_reverse, arginfo_array_reverse) PHP_FE(array_reduce, arginfo_array_reduce) PHP_FE(array_pad, arginfo_array_pad) diff --git a/ext/standard/php_array.h b/ext/standard/php_array.h index 991790c31ce51..1bf97018fba14 100644 --- a/ext/standard/php_array.h +++ b/ext/standard/php_array.h @@ -71,6 +71,7 @@ PHP_FUNCTION(array_replace_recursive); PHP_FUNCTION(array_keys); PHP_FUNCTION(array_values); PHP_FUNCTION(array_count_values); +PHP_FUNCTION(array_column); PHP_FUNCTION(array_reverse); PHP_FUNCTION(array_reduce); PHP_FUNCTION(array_pad); diff --git a/ext/standard/tests/array/array_column_basic.phpt b/ext/standard/tests/array/array_column_basic.phpt new file mode 100644 index 0000000000000..fa8fe2fb5a49e --- /dev/null +++ b/ext/standard/tests/array/array_column_basic.phpt @@ -0,0 +1,190 @@ +--TEST-- +Test array_column() function: basic functionality +--FILE-- + 1, + 'first_name' => 'John', + 'last_name' => 'Doe' + ), + array( + 'id' => 2, + 'first_name' => 'Sally', + 'last_name' => 'Smith' + ), + array( + 'id' => 3, + 'first_name' => 'Jane', + 'last_name' => 'Jones' + ) +); + +echo "-- first_name column from recordset --\n"; +var_dump(array_column($records, 'first_name')); + +echo "-- id column from recordset --\n"; +var_dump(array_column($records, 'id')); + +echo "\n*** Testing multiple data types ***\n"; +$file = basename(__FILE__); +$fh = fopen($file, 'r', true); +$values = array( + array( + 'id' => 1, + 'value' => new stdClass + ), + array( + 'id' => 2, + 'value' => 34.2345 + ), + array( + 'id' => 3, + 'value' => true + ), + array( + 'id' => 4, + 'value' => false + ), + array( + 'id' => 5, + 'value' => null + ), + array( + 'id' => 6, + 'value' => 1234 + ), + array( + 'id' => 7, + 'value' => 'Foo' + ), + array( + 'id' => 8, + 'value' => $fh + ) +); +var_dump(array_column($values, 'value')); + +echo "\n*** Testing numeric column keys ***\n"; +$numericCols = array( + array('aaa', '111'), + array('bbb', '222'), + array('ccc', '333') +); +var_dump(array_column($numericCols, 1)); + +echo "\n*** Testing failure to find specified column ***\n"; +var_dump(array_column($numericCols, 2)); +var_dump(array_column($numericCols, 'foo')); + +echo "\n*** Testing single dimensional array ***\n"; +$singleDimension = array('foo', 'bar', 'baz'); +var_dump(array_column($singleDimension, 1)); + +echo "\n*** Testing columns not present in all rows ***\n"; +$mismatchedColumns = array( + array('a' => 'foo', 'b' => 'bar'), + array('a' => 'baz', 'c' => 'qux'), +); +var_dump(array_column($mismatchedColumns, 'c')); + +echo "\n*** Testing use of object converted to string ***\n"; +class Foo +{ + public function __toString() + { + return 'last_name'; + } +} +$f = new Foo(); +var_dump(array_column($records, $f)); + +echo "Done\n"; +?> +--EXPECTF-- +*** Testing array_column() : basic functionality *** +-- first_name column from recordset -- +array(3) { + [0]=> + string(4) "John" + [1]=> + string(5) "Sally" + [2]=> + string(4) "Jane" +} +-- id column from recordset -- +array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) +} + +*** Testing multiple data types *** +array(8) { + [0]=> + object(stdClass)#1 (0) { + } + [1]=> + float(34.2345) + [2]=> + bool(true) + [3]=> + bool(false) + [4]=> + NULL + [5]=> + int(1234) + [6]=> + string(3) "Foo" + [7]=> + resource(5) of type (stream) +} + +*** Testing numeric column keys *** +array(3) { + [0]=> + string(3) "111" + [1]=> + string(3) "222" + [2]=> + string(3) "333" +} + +*** Testing failure to find specified column *** +array(0) { +} +array(0) { +} + +*** Testing single dimensional array *** +array(0) { +} + +*** Testing columns not present in all rows *** +array(1) { + [0]=> + string(3) "qux" +} + +*** Testing use of object converted to string *** +array(3) { + [0]=> + string(3) "Doe" + [1]=> + string(5) "Smith" + [2]=> + string(5) "Jones" +} +Done diff --git a/ext/standard/tests/array/array_column_error.phpt b/ext/standard/tests/array/array_column_error.phpt new file mode 100644 index 0000000000000..d409d3b12e088 --- /dev/null +++ b/ext/standard/tests/array/array_column_error.phpt @@ -0,0 +1,82 @@ +--TEST-- +Test array_column() function: error conditions +--FILE-- + +--EXPECTF-- +*** Testing array_column() : error conditions *** + +-- Testing array_column() function with Zero arguments -- + +Warning: array_column() expects exactly 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 +NULL + +-- Testing array_column() function with string as first parameter -- + +Warning: array_column() expects parameter 1 to be array, string given in %s on line %d +NULL + +-- Testing array_column() function with int as first parameter -- + +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) -- + +Warning: array_column(): The 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) -- + +Warning: array_column(): The 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) -- + +Warning: array_column(): The key should be either a string or an integer in %s on line %d +bool(false) +Done