summaryrefslogtreecommitdiff
path: root/ext/standard/array.c
diff options
context:
space:
mode:
authorXinchen Hui <laruence@php.net>2013-11-04 14:47:34 +0800
committerXinchen Hui <laruence@php.net>2013-11-04 14:47:34 +0800
commit2f555b8e606b5f09d635cef4d3fcbcd6939adae2 (patch)
treef2497158b9b7d575582b06d165e0b033bee6d19e /ext/standard/array.c
parent15eabbb43602ea7020ef7b6d99260e338fcc3aee (diff)
parente5e25c43f476456f5b342d4cd289d0ce5f8bbac4 (diff)
downloadphp-git-2f555b8e606b5f09d635cef4d3fcbcd6939adae2.tar.gz
Merge branch 'master' of git.php.net:php-src
Diffstat (limited to 'ext/standard/array.c')
-rw-r--r--ext/standard/array.c91
1 files changed, 69 insertions, 22 deletions
diff --git a/ext/standard/array.c b/ext/standard/array.c
index ae6e5d266f..17be59d6ca 100644
--- a/ext/standard/array.c
+++ b/ext/standard/array.c
@@ -127,6 +127,9 @@ PHP_MINIT_FUNCTION(array) /* {{{ */
REGISTER_LONG_CONSTANT("COUNT_NORMAL", COUNT_NORMAL, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("COUNT_RECURSIVE", COUNT_RECURSIVE, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("ARRAY_FILTER_USE_BOTH", ARRAY_FILTER_USE_BOTH, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("ARRAY_FILTER_USE_KEY", ARRAY_FILTER_USE_KEY, CONST_CS | CONST_PERSISTENT);
+
return SUCCESS;
}
/* }}} */
@@ -2223,13 +2226,14 @@ PHPAPI int php_array_merge(HashTable *dest, HashTable *src, int recursive TSRMLS
case HASH_KEY_IS_STRING:
if (recursive && zend_hash_find(dest, string_key, string_key_len, (void **)&dest_entry) == SUCCESS) {
HashTable *thash = Z_TYPE_PP(dest_entry) == IS_ARRAY ? Z_ARRVAL_PP(dest_entry) : NULL;
+ zval *src_zval;
+ zval *tmp = NULL;
if ((thash && thash->nApplyCount > 1) || (*src_entry == *dest_entry && Z_ISREF_PP(dest_entry) && (Z_REFCOUNT_PP(dest_entry) % 2))) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "recursion detected");
return 0;
}
SEPARATE_ZVAL(dest_entry);
- SEPARATE_ZVAL(src_entry);
if (Z_TYPE_PP(dest_entry) == IS_NULL) {
convert_to_array_ex(dest_entry);
@@ -2237,23 +2241,34 @@ PHPAPI int php_array_merge(HashTable *dest, HashTable *src, int recursive TSRMLS
} else {
convert_to_array_ex(dest_entry);
}
- if (Z_TYPE_PP(src_entry) == IS_NULL) {
- convert_to_array_ex(src_entry);
- add_next_index_null(*src_entry);
+ if (Z_TYPE_PP(src_entry) == IS_OBJECT) {
+ ALLOC_ZVAL(src_zval);
+ INIT_PZVAL_COPY(src_zval, *src_entry);
+ zval_copy_ctor(src_zval);
+ convert_to_array(src_zval);
+ tmp = src_zval;
} else {
- convert_to_array_ex(src_entry);
- }
- if (thash) {
- thash->nApplyCount++;
+ src_zval = *src_entry;
}
- if (!php_array_merge(Z_ARRVAL_PP(dest_entry), Z_ARRVAL_PP(src_entry), recursive TSRMLS_CC)) {
+ if (Z_TYPE_P(src_zval) == IS_ARRAY) {
+ if (thash) {
+ thash->nApplyCount++;
+ }
+ if (!php_array_merge(Z_ARRVAL_PP(dest_entry), Z_ARRVAL_P(src_zval), recursive TSRMLS_CC)) {
+ if (thash) {
+ thash->nApplyCount--;
+ }
+ return 0;
+ }
if (thash) {
thash->nApplyCount--;
}
- return 0;
+ } else {
+ Z_ADDREF_PP(src_entry);
+ zend_hash_next_index_insert(Z_ARRVAL_PP(dest_entry), &src_zval, sizeof(zval *), NULL);
}
- if (thash) {
- thash->nApplyCount--;
+ if (tmp) {
+ zval_ptr_dtor(&tmp);
}
} else {
Z_ADDREF_PP(src_entry);
@@ -2357,7 +2372,6 @@ static void php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAMETERS, int
array_init_size(return_value, init_size);
for (i = 0; i < argc; i++) {
- SEPARATE_ZVAL(args[i]);
if (!replace) {
php_array_merge(Z_ARRVAL_P(return_value), Z_ARRVAL_PP(args[i]), recursive TSRMLS_CC);
} else if (recursive && i > 0) { /* First array will be copied directly instead */
@@ -4194,9 +4208,11 @@ PHP_FUNCTION(array_filter)
{
zval *array;
zval **operand;
- zval **args[1];
+ zval **args[2];
zval *retval = NULL;
+ zval *key = NULL;
zend_bool have_callback = 0;
+ long use_type = 0;
char *string_key;
zend_fcall_info fci = empty_fcall_info;
zend_fcall_info_cache fci_cache = empty_fcall_info_cache;
@@ -4204,7 +4220,7 @@ PHP_FUNCTION(array_filter)
ulong num_key;
HashPosition pos;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|f", &array, &fci, &fci_cache) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|fl", &array, &fci, &fci_cache, &use_type) == FAILURE) {
return;
}
@@ -4217,23 +4233,54 @@ PHP_FUNCTION(array_filter)
have_callback = 1;
fci.no_separation = 0;
fci.retval_ptr_ptr = &retval;
- fci.param_count = 1;
+
+ if (use_type == ARRAY_FILTER_USE_BOTH) {
+ fci.param_count = 2;
+ args[1] = &key;
+ } else {
+ fci.param_count = 1;
+ if (use_type == ARRAY_FILTER_USE_KEY) {
+ args[0] = &key;
+ }
+ }
}
for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(array), &pos);
zend_hash_get_current_data_ex(Z_ARRVAL_P(array), (void **)&operand, &pos) == SUCCESS;
zend_hash_move_forward_ex(Z_ARRVAL_P(array), &pos)
) {
+ int key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(array), &string_key, &string_key_len, &num_key, 0, &pos);
+
if (have_callback) {
- args[0] = operand;
+ if (use_type) {
+ MAKE_STD_ZVAL(key);
+ /* Set up the key */
+ switch (key_type) {
+ case HASH_KEY_IS_LONG:
+ Z_TYPE_P(key) = IS_LONG;
+ Z_LVAL_P(key) = num_key;
+ break;
+
+ case HASH_KEY_IS_STRING:
+ ZVAL_STRINGL(key, string_key, string_key_len - 1, 1);
+ break;
+ }
+ }
+
+ if (use_type != ARRAY_FILTER_USE_KEY) {
+ args[0] = operand;
+ }
fci.params = args;
if (zend_call_function(&fci, &fci_cache TSRMLS_CC) == SUCCESS && retval) {
- if (!zend_is_true(retval)) {
- zval_ptr_dtor(&retval);
+ int retval_true = zend_is_true(retval);
+
+ zval_ptr_dtor(&retval);
+ if (use_type) {
+ zval_ptr_dtor(&key);
+ }
+ if (!retval_true) {
continue;
- } else {
- zval_ptr_dtor(&retval);
}
} else {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "An error occurred while invoking the filter callback");
@@ -4244,7 +4291,7 @@ PHP_FUNCTION(array_filter)
}
zval_add_ref(operand);
- switch (zend_hash_get_current_key_ex(Z_ARRVAL_P(array), &string_key, &string_key_len, &num_key, 0, &pos)) {
+ switch (key_type) {
case HASH_KEY_IS_STRING:
zend_hash_update(Z_ARRVAL_P(return_value), string_key, string_key_len, operand, sizeof(zval *), NULL);
break;