diff options
author | Tjerk Meesters <datibbaw@php.net> | 2015-06-27 07:35:44 +0800 |
---|---|---|
committer | Tjerk Meesters <datibbaw@php.net> | 2015-06-27 07:35:44 +0800 |
commit | 3bf012a98d2f47b84e4632a58aa14f8a45149041 (patch) | |
tree | 811c716c7a35086203e4a727fd7e5eb0029a7a30 | |
parent | 86df85f43a74836ac3321fd0b85401bb14f1f668 (diff) | |
download | php-git-3bf012a98d2f47b84e4632a58aa14f8a45149041.tar.gz |
Feature: Enhanced array_column() to also work with object elements.
-rw-r--r-- | UPGRADING | 5 | ||||
-rw-r--r-- | ext/standard/array.c | 51 | ||||
-rw-r--r-- | ext/standard/tests/array/array_column_variant_objects.phpt | 165 |
3 files changed, 202 insertions, 19 deletions
@@ -610,6 +610,11 @@ Other hardcoded value of 16. This limit is now removed and the number of pipes is effectively limited by the amount of memory available to PHP. +- array_column(): + The function now supports an array of objects as well as two-dimensional + arrays. Only public properties are considered, and objects that make use of + __get() for dynamic properties must also implement __isset(). + ======================================== 6. New Functions ======================================== diff --git a/ext/standard/array.c b/ext/standard/array.c index 1cf5da1d01..5341544b39 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -3068,6 +3068,28 @@ zend_bool array_column_param_helper(zval *param, } /* }}} */ +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 */ @@ -3075,8 +3097,7 @@ PHP_FUNCTION(array_column) { 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; @@ -3090,32 +3111,18 @@ PHP_FUNCTION(array_column) 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); @@ -3130,6 +3137,12 @@ PHP_FUNCTION(array_column) } 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(); } /* }}} */ diff --git a/ext/standard/tests/array/array_column_variant_objects.phpt b/ext/standard/tests/array/array_column_variant_objects.phpt new file mode 100644 index 0000000000..80e1839736 --- /dev/null +++ b/ext/standard/tests/array/array_column_variant_objects.phpt @@ -0,0 +1,165 @@ +--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 |