1
0
mirror of https://github.com/php/php-src.git synced 2026-04-08 08:33:06 +02:00

Merge branch 'PHP-5.5'

* PHP-5.5:
  NEWS for array_column
  array_column: Fix compile-time warnings
  array_column: Removed array_pluck() alias
  array_column: Set array_pluck as an alias for array_column
  array_column: Implement ability to specify an index column
  Cleaning up a memory leak.
  array_column: Adding test for IS_OBJECT and converting object to string
  array_column: Using add_next_index_zval() at nikic's recommendation.
  array_column: Improved tests
  array_column: Cleaning up, as recommended in pull request #56 comments
  Fixing typo in test for array_column()
  Simplify the code and use zend_hash_next_index_insert()
  Adding test for columns not present in all rows for array_column().
  Adding tests for the negative results of array_column()
  Implement new array function array_column()
This commit is contained in:
David Soria Parra
2013-03-20 13:14:33 +01:00
5 changed files with 528 additions and 0 deletions

View File

@@ -2524,6 +2524,121 @@ PHP_FUNCTION(array_count_values)
}
/* }}} */
/* {{{ 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, *zcolumn, *zkey = NULL, **data, **zcolval, **zkeyval;
HashTable *arr_hash;
HashPosition pointer;
ulong column_idx = 0, key_idx = 0;
char *column = NULL, *key = NULL, *keyval = NULL;
int column_len = 0, key_len = 0, keyval_idx = -1;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "az|z", &zarray, &zcolumn, &zkey) == FAILURE) {
return;
}
switch (Z_TYPE_P(zcolumn)) {
case IS_NULL:
column_idx = 0;
break;
case IS_LONG:
column_idx = Z_LVAL_P(zcolumn);
break;
case IS_STRING:
column = Z_STRVAL_P(zcolumn);
column_len = Z_STRLEN_P(zcolumn);
break;
case IS_OBJECT:
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 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);
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 (column && zend_hash_find(Z_ARRVAL_PP(data), column, column_len + 1, (void**)&zcolval) == FAILURE) {
continue;
} else if (!column && zend_hash_index_find(Z_ARRVAL_PP(data), column_idx, (void**)&zcolval) == FAILURE) {
continue;
}
Z_ADDREF_PP(zcolval);
keyval = NULL;
keyval_idx = -1;
if (zkey) {
if (key && zend_hash_find(Z_ARRVAL_PP(data), key, key_len + 1, (void**)&zkeyval) == FAILURE) {
keyval_idx = -1;
} else if (!key && zend_hash_index_find(Z_ARRVAL_PP(data), key_idx, (void**)&zkeyval) == FAILURE) {
keyval_idx = -1;
} 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 = -1;
}
}
}
if (keyval) {
add_assoc_zval(return_value, keyval, *zcolval);
} else if (keyval_idx != -1) {
add_index_zval(return_value, keyval_idx, *zcolval);
} else {
add_next_index_zval(return_value, *zcolval);
}
}
}
}
/* }}} */
/* {{{ 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

@@ -436,6 +436,12 @@ 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, column_key)
ZEND_ARG_INFO(0, index_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)
@@ -3323,6 +3329,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,307 @@
--TEST--
Test array_column() function: basic functionality
--FILE--
<?php
/* Prototype:
* array array_column(array $input, mixed $column_key[, mixed $index_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 "-- last_name column from recordset, keyed by value from id column --\n";
var_dump(array_column($records, 'last_name', 'id'));
echo "-- last_name column from recordset, keyed by value from first_name column --\n";
var_dump(array_column($records, 'last_name', 'first_name'));
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'));
var_dump(array_column($values, 'value', 'id'));
echo "\n*** Testing numeric column keys ***\n";
$numericCols = array(
array('aaa', '111'),
array('bbb', '222'),
array('ccc', '333')
);
var_dump(array_column($numericCols, 1));
var_dump(array_column($numericCols, 1, 0));
echo "\n*** Testing failure to find specified column ***\n";
var_dump(array_column($numericCols, 2));
var_dump(array_column($numericCols, 'foo'));
var_dump(array_column($numericCols, 0, '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', '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
{
public function __toString()
{
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";
?>
--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)
}
-- 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) {
[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)
}
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) {
[0]=>
string(3) "111"
[1]=>
string(3) "222"
[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) {
}
*** Testing columns not present in all rows ***
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) {
[0]=>
string(3) "Doe"
[1]=>
string(5) "Smith"
[2]=>
string(5) "Jones"
}
array(3) {
["John"]=>
string(3) "Doe"
["Sally"]=>
string(5) "Smith"
["Jane"]=>
string(5) "Jones"
}
Done

View File

@@ -0,0 +1,98 @@
--TEST--
Test array_column() function: error conditions
--FILE--
<?php
/* Prototype:
* array array_column(array $input, mixed $column_key[, mixed $index_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 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() column key parameter should be a string or an integer (testing bool) --\n";
var_dump(array_column(array(), true));
echo "\n-- Testing array_column() column key parameter should be a string or integer (testing float) --\n";
var_dump(array_column(array(), 2.3));
echo "\n-- Testing array_column() column key parameter should be a string or integer (testing array) --\n";
var_dump(array_column(array(), array()));
echo "\n-- Testing array_column() index key parameter should be a string or an integer (testing bool) --\n";
var_dump(array_column(array(), 'foo', true));
echo "\n-- Testing array_column() index key parameter should be a string or integer (testing float) --\n";
var_dump(array_column(array(), 'foo', 2.3));
echo "\n-- Testing array_column() index key parameter should be a string or integer (testing array) --\n";
var_dump(array_column(array(), 'foo', array()));
echo "Done\n";
?>
--EXPECTF--
*** Testing array_column() : error conditions ***
-- Testing array_column() function with Zero arguments --
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 at least 2 parameters, 1 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() 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 index 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 integer (testing float) --
Warning: array_column(): The index 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 integer (testing array) --
Warning: array_column(): The index key should be either a string or an integer in %s on line %d
bool(false)
Done