Implement new array function array_column()

array_column() returns the values of the specified column from a
multi-dimensional array.
This commit is contained in:
Ben Ramsey 2012-04-13 23:17:56 -05:00
parent e1410b5a70
commit 9035a1ed24
4 changed files with 226 additions and 0 deletions

View File

@ -2563,6 +2563,87 @@ 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;
}
arr_hash = Z_ARRVAL_P(zarray);
array_init(return_value);
switch (Z_TYPE_P(zoffset)) {
case IS_NULL:
index = 0;
break;
case IS_DOUBLE:
index = (long)Z_DVAL_P(zoffset);
break;
case IS_BOOL:
case IS_LONG:
case IS_RESOURCE:
index = Z_LVAL_P(zoffset);
break;
case IS_STRING:
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;
}
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;
}
switch (Z_TYPE_PP(zvalue)) {
case IS_NULL:
add_next_index_null(return_value);
break;
case IS_LONG:
add_next_index_long(return_value, Z_LVAL_PP(zvalue));
break;
case IS_DOUBLE:
add_next_index_double(return_value, Z_DVAL_PP(zvalue));
break;
case IS_BOOL:
add_next_index_bool(return_value, Z_BVAL_PP(zvalue));
break;
case IS_OBJECT:
zval_add_ref(zvalue);
add_next_index_zval(return_value, *zvalue);
break;
case IS_STRING:
add_next_index_stringl(return_value, Z_STRVAL_PP(zvalue), Z_STRLEN_PP(zvalue), 1);
break;
case IS_RESOURCE:
zval_add_ref(zvalue);
add_next_index_resource(return_value, Z_RESVAL_PP(zvalue));
break;
}
}
}
}
/* }}} */
/* {{{ 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)

View File

@ -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 File

@ -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);

View File

@ -0,0 +1,138 @@
--TEST--
Test array_column_values() function
--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 basic functionalities ***\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 "Done\n";
?>
--EXPECTF--
*** Testing basic functionalities ***
-- 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"
}
Done