}
/* }}} */
+static inline zval *array_column_fetch_prop(zval *data, zval *name, zval *rv)
+{
+ zval *prop = NULL;
+
+ if (Z_TYPE_P(data) == IS_OBJECT) {
+ zend_string *key = zval_get_string(name);
+
+ if (!Z_OBJ_HANDLER_P(data, has_property) || Z_OBJ_HANDLER_P(data, has_property)(data, name, 1, NULL)) {
+ prop = zend_read_property(Z_OBJCE_P(data), data, key->val, key->len, 1, rv);
+ }
+ zend_string_release(key);
+ } else if (Z_TYPE_P(data) == IS_ARRAY) {
+ if (Z_TYPE_P(name) == IS_STRING) {
+ prop = zend_hash_find(Z_ARRVAL_P(data), Z_STR_P(name));
+ } else if (Z_TYPE_P(name) == IS_LONG) {
+ prop = zend_hash_index_find(Z_ARRVAL_P(data), Z_LVAL_P(name));
+ }
+ }
+
+ return prop;
+}
+
/* {{{ 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 */
{
zval *zcolumn = NULL, *zkey = NULL, *data;
HashTable *arr_hash;
- zval *zcolval = NULL, *zkeyval = NULL;
- HashTable *ht;
+ zval *zcolval = NULL, *zkeyval = NULL, rvc, rvk;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "hz!|z!", &arr_hash, &zcolumn, &zkey) == FAILURE) {
return;
array_init(return_value);
ZEND_HASH_FOREACH_VAL(arr_hash, data) {
ZVAL_DEREF(data);
- if (Z_TYPE_P(data) != IS_ARRAY) {
- /* Skip elemens which are not sub-arrays */
- continue;
- }
- ht = Z_ARRVAL_P(data);
if (!zcolumn) {
- /* NULL column ID means use entire subarray as data */
zcolval = data;
-
- /* Otherwise, skip if the value doesn't exist in our subarray */
- } else if ((Z_TYPE_P(zcolumn) == IS_STRING) &&
- ((zcolval = zend_hash_find(ht, Z_STR_P(zcolumn))) == NULL)) {
- continue;
- } else if ((Z_TYPE_P(zcolumn) == IS_LONG) &&
- ((zcolval = zend_hash_index_find(ht, Z_LVAL_P(zcolumn))) == NULL)) {
+ } else if ((zcolval = array_column_fetch_prop(data, zcolumn, &rvc)) == NULL) {
continue;
}
/* Failure will leave zkeyval alone which will land us on the final else block below
* which is to append the value as next_index
*/
- if (zkey && (Z_TYPE_P(zkey) == IS_STRING)) {
- zkeyval = zend_hash_find(ht, Z_STR_P(zkey));
- } else if (zkey && (Z_TYPE_P(zkey) == IS_LONG)) {
- zkeyval = zend_hash_index_find(ht, Z_LVAL_P(zkey));
+ if (zkey) {
+ zkeyval = array_column_fetch_prop(data, zkey, &rvk);
}
Z_TRY_ADDREF_P(zcolval);
} else {
add_next_index_zval(return_value, zcolval);
}
+ if (zcolval == &rvc) {
+ zval_ptr_dtor(&rvc);
+ }
+ if (zkeyval == &rvk) {
+ zval_ptr_dtor(&rvk);
+ }
} ZEND_HASH_FOREACH_END();
}
/* }}} */
--- /dev/null
+--TEST--
+Test array_column() function: testing with objects
+--FILE--
+<?php
+
+class User
+{
+ public $id, $first_name, $last_name;
+
+ public function __construct($id, $first_name, $last_name)
+ {
+ $this->id = $id;
+ $this->first_name = $first_name;
+ $this->last_name = $last_name;
+ }
+}
+
+function newUser($id, $first_name, $last_name)
+{
+ $o = new stdClass;
+ $o->{0} = $id;
+ $o->{1} = $first_name;
+ $o->{2} = $last_name;
+
+ return $o;
+}
+
+class Something
+{
+ public function __isset($name)
+ {
+ return $name == 'first_name';
+ }
+
+ public function __get($name)
+ {
+ return new User(4, 'Jack', 'Sparrow');
+ }
+}
+
+$records = array(
+ newUser(1, 'John', 'Doe'),
+ newUser(2, 'Sally', 'Smith'),
+ newUser(3, 'Jane', 'Jones'),
+ new User(1, 'John', 'Doe'),
+ new User(2, 'Sally', 'Smith'),
+ new User(3, 'Jane', 'Jones'),
+ new Something,
+);
+
+echo "*** Testing array_column() : object property fetching (numeric property names) ***\n";
+
+echo "-- first_name column from recordset --\n";
+var_dump(array_column($records, 1));
+
+echo "-- id column from recordset --\n";
+var_dump(array_column($records, 0));
+
+echo "-- last_name column from recordset, keyed by value from id column --\n";
+var_dump(array_column($records, 2, 0));
+
+echo "-- last_name column from recordset, keyed by value from first_name column --\n";
+var_dump(array_column($records, 2, 1));
+
+echo "*** Testing array_column() : object property fetching (string property names) ***\n";
+
+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 "Done\n";
+?>
+--EXPECTF--
+*** Testing array_column() : object property fetching (numeric property names) ***
+-- 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 array_column() : object property fetching (string property names) ***
+-- first_name column from recordset --
+array(4) {
+ [0]=>
+ string(4) "John"
+ [1]=>
+ string(5) "Sally"
+ [2]=>
+ string(4) "Jane"
+ [3]=>
+ object(User)#8 (3) {
+ ["id"]=>
+ int(4)
+ ["first_name"]=>
+ string(4) "Jack"
+ ["last_name"]=>
+ string(7) "Sparrow"
+ }
+}
+-- 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"
+}
+Done