Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

Implement new array function array_column() #56

Closed
wants to merge 12 commits into
from
View
@@ -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)
@@ -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)
View
@@ -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);
@@ -0,0 +1,190 @@
+--TEST--
+Test array_column() function: basic functionality
+--FILE--
+<?php
+/* Prototype:
+ * array array_column(array $input, mixed $key);
+ * Description:
+ * Returns an array containing all the values from
+ * the specified "column" in a two-dimensional array.
+ */
+
+echo "*** Testing array_column() : basic functionality ***\n";
+/* Array representing a possible record set returned from a database */
+$records = array(
+ array(
+ 'id' => 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
@@ -0,0 +1,82 @@
+--TEST--
+Test array_column() function: error conditions
+--FILE--
+<?php
+/* Prototype:
+ * array array_column(array $input, mixed $key);
+ * Description:
+ * Returns an array containing all the values from
+ * the specified "column" in a two-dimensional array.
+ */
+
+echo "*** Testing array_column() : error conditions ***\n";
+
+echo "\n-- Testing array_column() function with Zero arguments --\n";
+var_dump(array_column());
+
+echo "\n-- Testing array_column() function with One argument --\n";
+var_dump(array_column(array()));
+
+echo "\n-- Testing array_column() function with more than expected no. of arguments --\n";
+var_dump(array_column(array(), 'foo', 'bar'));
+
+echo "\n-- Testing array_column() function with string as first parameter --\n";
+var_dump(array_column('foo', 0));
+
+echo "\n-- Testing array_column() function with int as first parameter --\n";
+var_dump(array_column(1, 'foo'));
+
+echo "\n-- Testing array_column() key parameter should be a string or an integer (testing bool) --\n";
+var_dump(array_column(array(), true));
+
+echo "\n-- Testing array_column() key parameter should be a string or integer (testing float) --\n";
+var_dump(array_column(array(), 2.3));
+
+echo "\n-- Testing array_column() key parameter should be a string or integer (testing array) --\n";
+var_dump(array_column(array(), array()));
+
+echo "Done\n";
+?>
+--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