summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTjerk Meesters <datibbaw@php.net>2015-06-27 07:35:44 +0800
committerTjerk Meesters <datibbaw@php.net>2015-06-27 07:35:44 +0800
commit3bf012a98d2f47b84e4632a58aa14f8a45149041 (patch)
tree811c716c7a35086203e4a727fd7e5eb0029a7a30
parent86df85f43a74836ac3321fd0b85401bb14f1f668 (diff)
downloadphp-git-3bf012a98d2f47b84e4632a58aa14f8a45149041.tar.gz
Feature: Enhanced array_column() to also work with object elements.
-rw-r--r--UPGRADING5
-rw-r--r--ext/standard/array.c51
-rw-r--r--ext/standard/tests/array/array_column_variant_objects.phpt165
3 files changed, 202 insertions, 19 deletions
diff --git a/UPGRADING b/UPGRADING
index d1d3fd51cd..ae2989eb5d 100644
--- a/UPGRADING
+++ b/UPGRADING
@@ -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