Use standard key behavior in array_column()

array_column() reimplements array key handling in a way that does
not match standard array key behavior in PHP. Avoid this by making
use of the standard API.

Of course, there is a minor backwards compatibilty break here,
e.g. people could be relying on objects getting cast to string
instead of throwing.

Closes GH-5487.
This commit is contained in:
Nikita Popov 2020-04-29 10:35:44 +02:00
parent b111674383
commit 091d53c131
3 changed files with 23 additions and 51 deletions

View file

@ -4174,48 +4174,11 @@ PHP_FUNCTION(array_column)
continue; continue;
} }
/* Failure will leave keyval alone which will land us on the final else block below
* which is to append the value as next_index
*/
zval rv; zval rv;
zval *keyval = array_column_fetch_prop(data, index_str, index_long, &rv); zval *keyval = array_column_fetch_prop(data, index_str, index_long, &rv);
if (keyval) { if (keyval) {
switch (Z_TYPE_P(keyval)) { array_set_zval_key(Z_ARRVAL_P(return_value), keyval, colval);
case IS_STRING: zval_ptr_dtor(colval);
zend_symtable_update(Z_ARRVAL_P(return_value), Z_STR_P(keyval), colval);
break;
case IS_LONG:
zend_hash_index_update(Z_ARRVAL_P(return_value), Z_LVAL_P(keyval), colval);
break;
case IS_OBJECT:
{
zend_string *tmp_key;
zend_string *key = zval_get_tmp_string(keyval, &tmp_key);
zend_symtable_update(Z_ARRVAL_P(return_value), key, colval);
zend_tmp_string_release(tmp_key);
break;
}
case IS_NULL:
zend_hash_update(Z_ARRVAL_P(return_value), ZSTR_EMPTY_ALLOC(), colval);
break;
case IS_DOUBLE:
zend_hash_index_update(Z_ARRVAL_P(return_value),
zend_dval_to_lval(Z_DVAL_P(keyval)), colval);
break;
case IS_TRUE:
zend_hash_index_update(Z_ARRVAL_P(return_value), 1, colval);
break;
case IS_FALSE:
zend_hash_index_update(Z_ARRVAL_P(return_value), 0, colval);
break;
case IS_RESOURCE:
zend_hash_index_update(Z_ARRVAL_P(return_value), Z_RES_HANDLE_P(keyval), colval);
break;
default:
zend_hash_next_index_insert(Z_ARRVAL_P(return_value), colval);
break;
}
zval_ptr_dtor(keyval); zval_ptr_dtor(keyval);
} else { } else {
zend_hash_next_index_insert(Z_ARRVAL_P(return_value), colval); zend_hash_next_index_insert(Z_ARRVAL_P(return_value), colval);

View file

@ -10,20 +10,15 @@ class IndexKeyClass {
function __toString() { return 'id'; } function __toString() { return 'id'; }
} }
class ValueClass {
function __toString() { return '2135'; }
}
$column_key = new ColumnKeyClass(); $column_key = new ColumnKeyClass();
$index_key = new IndexKeyClass(); $index_key = new IndexKeyClass();
$value = new ValueClass();
// Array representing a possible record set returned from a database // Array representing a possible record set returned from a database
$records = array( $records = array(
array( array(
'id' => $value, 'id' => 2135,
'first_name' => 'John', 'first_name' => 'John',
'last_name' => 'XXX' 'last_name' => 'XXX'
), ),
@ -37,16 +32,15 @@ $firstNames = array_column($records, $column_key, $index_key);
print_r($firstNames); print_r($firstNames);
var_dump($column_key); var_dump($column_key);
var_dump($index_key); var_dump($index_key);
var_dump($value);
--EXPECTF-- ?>
--EXPECT--
Array Array
( (
[2135] => John [2135] => John
[3245] => Sally [3245] => Sally
) )
object(ColumnKeyClass)#%d (0) { object(ColumnKeyClass)#1 (0) {
} }
object(IndexKeyClass)#%d (0) { object(IndexKeyClass)#2 (0) {
}
object(ValueClass)#%d (0) {
} }

View file

@ -21,7 +21,20 @@ $a = [
]; ];
var_dump(array_column($a, null, 'a')); var_dump(array_column($a, null, 'a'));
try {
var_dump(array_column([['a' => new stdClass]], null, 'a'));
} catch (Error $e) {
echo $e->getMessage(), "\n";
}
try {
var_dump(array_column([['a' => []]], null, 'a'));
} catch (Error $e) {
echo $e->getMessage(), "\n";
}
?>
--EXPECTF-- --EXPECTF--
Warning: Resource ID#%d used as offset, casting to integer (%d) in %s on line %d
array(8) { array(8) {
[10]=> [10]=>
array(1) { array(1) {
@ -64,3 +77,5 @@ array(8) {
NULL NULL
} }
} }
Illegal offset type
Illegal offset type