From 1a03bd5dee97a0f8b9e74b7f8db5231abd8cc7e4 Mon Sep 17 00:00:00 2001 From: Sara Golemon Date: Mon, 22 Apr 2013 14:57:05 -0700 Subject: [PATCH] Allow array_column() to take -1 as a valid value in third param Also do some cleanup and simplification to make this code more readable in the long term. --- ext/standard/array.c | 173 +++++++----------- .../tests/array/array_column_basic.phpt | 11 +- 2 files changed, 78 insertions(+), 106 deletions(-) diff --git a/ext/standard/array.c b/ext/standard/array.c index 425d53e388..6f769da1d8 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -2524,132 +2524,95 @@ PHP_FUNCTION(array_count_values) } /* }}} */ +/* {{{ array_column_param_helper + * Specialized conversion rules for array_column() function + */ +static inline +zend_bool array_column_param_helper(zval **param, + const char *name TSRMLS_DC) { + switch (Z_TYPE_PP(param)) { + case IS_NULL: + case IS_DOUBLE: + convert_to_long_ex(param); + /* fallthrough */ + case IS_LONG: + return 1; + + case IS_OBJECT: + convert_to_string_ex(param); + /* fallthrough */ + case IS_STRING: + return 1; + + default: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "The %s key should be either a string or an integer", name); + return 0; + } +} + /* {{{ 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; + zval **zcolumn, **zkey = NULL, **data; 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) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "hZ|Z!", &arr_hash, &zcolumn, &zkey) == FAILURE) { return; } - switch (Z_TYPE_PP(zcolumn)) { - case IS_NULL: - column_idx = 0; - break; - case IS_LONG: - column_idx = Z_LVAL_PP(zcolumn); - break; - case IS_DOUBLE: - column_idx = (long)Z_DVAL_PP(zcolumn); - break; - case IS_STRING: - column = Z_STRVAL_PP(zcolumn); - column_len = Z_STRLEN_PP(zcolumn); - break; - case IS_OBJECT: - convert_to_string_ex(zcolumn); - column = Z_STRVAL_PP(zcolumn); - column_len = Z_STRLEN_PP(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_PP(zkey)) { - case IS_NULL: - key_idx = 0; - break; - case IS_LONG: - key_idx = Z_LVAL_PP(zkey); - break; - case IS_DOUBLE: - key_idx = (long)Z_DVAL_PP(zkey); - break; - case IS_STRING: - key = Z_STRVAL_PP(zkey); - key_len = Z_STRLEN_PP(zkey); - break; - case IS_OBJECT: - convert_to_string_ex(zkey); - key = Z_STRVAL_PP(zkey); - key_len = Z_STRLEN_PP(zkey); - break; - default: - php_error_docref(NULL TSRMLS_CC, E_WARNING, "The index key should be either a string or an integer"); - RETURN_FALSE; - } + if (!array_column_param_helper(zcolumn, "column" TSRMLS_CC) || + (zkey && !array_column_param_helper(zkey, "index" TSRMLS_CC))) { + 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)) { + zval **zcolval, **zkeyval = NULL; + HashTable *ht; - if (Z_TYPE_PP(data) == IS_ARRAY) { - zval *strkey = NULL; - - 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: - { - MAKE_STD_ZVAL(strkey); - MAKE_COPY_ZVAL(zkeyval, strkey); - convert_to_string(strkey); - keyval = Z_STRVAL_P(strkey); - } - break; - default: - keyval_idx = -1; - } - } - } + if (Z_TYPE_PP(data) != IS_ARRAY) { + /* Skip elemens which are not sub-arrays */ + continue; + } + ht = Z_ARRVAL_PP(data); - if (keyval) { - add_assoc_zval(return_value, keyval, *zcolval); - if (strkey) { - zval_ptr_dtor(&strkey); - } - } else if (keyval_idx != -1) { - add_index_zval(return_value, keyval_idx, *zcolval); - } else { - add_next_index_zval(return_value, *zcolval); - } + /* Skip if the value doesn't exist in our subarray */ + if ((Z_TYPE_PP(zcolumn) == IS_STRING) && + (zend_hash_find(ht, Z_STRVAL_PP(zcolumn), Z_STRLEN_PP(zcolumn) + 1, (void**)&zcolval) == FAILURE)) { + continue; + } else if ((Z_TYPE_PP(zcolumn) == IS_LONG) && + (zend_hash_index_find(ht, Z_LVAL_PP(zcolumn), (void**)&zcolval) == FAILURE)) { + 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_PP(zkey) == IS_STRING)) { + zend_hash_find(ht, Z_STRVAL_PP(zkey), Z_STRLEN_PP(zkey) + 1, (void**)&zkeyval); + } else if (zkey && (Z_TYPE_PP(zkey) == IS_LONG)) { + zend_hash_index_find(ht, Z_LVAL_PP(zkey), (void**)&zkeyval); + } + + Z_ADDREF_PP(zcolval); + if (zkeyval && Z_TYPE_PP(zkeyval) == IS_STRING) { + add_assoc_zval(return_value, Z_STRVAL_PP(zkeyval), *zcolval); + } else if (zkeyval && Z_TYPE_PP(zkeyval) == IS_LONG) { + add_index_zval(return_value, Z_LVAL_PP(zkeyval), *zcolval); + } else if (zkeyval && Z_TYPE_PP(zkeyval) == IS_OBJECT) { + zval copyval; + ZVAL_ZVAL(©val, *zkeyval, 1, 0); + convert_to_string(©val); + add_assoc_zval(return_value, Z_STRVAL(copyval), *zcolval); + zval_dtor(©val); + } else { + add_next_index_zval(return_value, *zcolval); + } } } /* }}} */ diff --git a/ext/standard/tests/array/array_column_basic.phpt b/ext/standard/tests/array/array_column_basic.phpt index eb267dad73..7c30cdfd10 100644 --- a/ext/standard/tests/array/array_column_basic.phpt +++ b/ext/standard/tests/array/array_column_basic.phpt @@ -84,11 +84,12 @@ echo "\n*** Testing numeric column keys ***\n"; $numericCols = array( array('aaa', '111'), array('bbb', '222'), - array('ccc', '333') + array('ccc', '333', -1 => 'ddd') ); var_dump(array_column($numericCols, 1)); var_dump(array_column($numericCols, 1, 0)); var_dump(array_column($numericCols, 1, 0.123)); +var_dump(array_column($numericCols, 1, -1)); echo "\n*** Testing failure to find specified column ***\n"; var_dump(array_column($numericCols, 2)); @@ -239,6 +240,14 @@ array(3) { ["ccc"]=> string(3) "333" } +array(3) { + [0]=> + string(3) "111" + [1]=> + string(3) "222" + ["ddd"]=> + string(3) "333" +} *** Testing failure to find specified column *** array(0) { -- 2.40.0