Index: ext/standard/array.c =================================================================== RCS file: /repository/php-src/ext/standard/array.c,v retrieving revision 1.308.2.21.2.9 diff -u -r1.308.2.21.2.9 array.c --- ext/standard/array.c 30 Jul 2006 03:31:18 -0000 1.308.2.21.2.9 +++ ext/standard/array.c 5 Aug 2006 10:32:00 -0000 @@ -2326,15 +2326,14 @@ Z_ARRVAL_PP(src_entry), recursive TSRMLS_CC)) return 0; } else { - (*src_entry)->refcount++; - + ZVAL_ADDREF(*src_entry); zend_hash_update(dest, string_key, string_key_len, src_entry, sizeof(zval *), NULL); } break; case HASH_KEY_IS_LONG: - (*src_entry)->refcount++; + ZVAL_ADDREF(*src_entry); zend_hash_next_index_insert(dest, src_entry, sizeof(zval *), NULL); break; } @@ -2345,7 +2344,64 @@ return 1; } -static void php_array_merge_wrapper(INTERNAL_FUNCTION_PARAMETERS, int recursive) +PHPAPI int php_array_replace_recursive(HashTable *dest, HashTable *src TSRMLS_DC) +{ + zval **src_entry, **dest_entry; + char *string_key; + uint string_key_len; + ulong num_key; + HashPosition pos; + + zend_hash_internal_pointer_reset_ex(src, &pos); + while (zend_hash_get_current_data_ex(src, (void **)&src_entry, &pos) == SUCCESS) { + zend_bool recursive = 0; + + switch (zend_hash_get_current_key_ex(src, &string_key, &string_key_len, &num_key, 0, &pos)) { + case HASH_KEY_IS_STRING: + if (Z_TYPE_PP(src_entry) == IS_ARRAY && + zend_hash_find(dest, string_key, string_key_len, (void **)&dest_entry) == SUCCESS && + Z_TYPE_PP(dest_entry) == IS_ARRAY) { + + recursive = 1; + } else { + ZVAL_ADDREF(*src_entry); + zend_hash_update(dest, string_key, string_key_len, + src_entry, sizeof(zval *), NULL); + } + break; + + case HASH_KEY_IS_LONG: + if (Z_TYPE_PP(src_entry) == IS_ARRAY && + zend_hash_index_find(dest, num_key, (void **)&dest_entry) == SUCCESS && + Z_TYPE_PP(dest_entry) == IS_ARRAY) { + + recursive = 1; + } else { + ZVAL_ADDREF(*src_entry); + zend_hash_index_update(dest, num_key, src_entry, sizeof(zval *), NULL); + } + break; + } + + if (recursive) { + if (*src_entry == *dest_entry && ((*dest_entry)->refcount % 2)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "recursion detected"); + return 0; + } + SEPARATE_ZVAL(dest_entry); + + if (!php_array_replace_recursive(Z_ARRVAL_PP(dest_entry), Z_ARRVAL_PP(src_entry) TSRMLS_CC)) { + return 0; + } + } + + zend_hash_move_forward_ex(src, &pos); + } + + return 1; +} + +static void php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAMETERS, int recursive, int replace) { zval ***args = NULL; int argc, i, params_ok = 1; @@ -2376,10 +2432,15 @@ array_init(return_value); - for (i=0; i 0) { /* First array will be copied directly instead */ + php_array_replace_recursive(Z_ARRVAL_P(return_value), Z_ARRVAL_PP(args[i]) TSRMLS_CC); + } else { + zval *tmp; + zend_hash_copy(Z_ARRVAL_P(return_value), Z_ARRVAL_PP(args[i]), (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); + } } efree(args); @@ -2390,7 +2451,7 @@ Merges elements from passed arrays into one array */ PHP_FUNCTION(array_merge) { - php_array_merge_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); + php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 0); } /* }}} */ @@ -2399,7 +2460,25 @@ Recursively merges elements from passed arrays into one array */ PHP_FUNCTION(array_merge_recursive) { - php_array_merge_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); + php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, 0); +} +/* }}} */ + + +/* {{{ proto array array_replace(array arr1, array arr2 [, array ...]) + Replaces elements from passed arrays into one array */ +PHP_FUNCTION(array_replace) +{ + php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 1); +} +/* }}} */ + + +/* {{{ proto array array_replace_recursive(array arr1, array arr2 [, array ...]) + Recursively replaces elements from passed arrays into one array */ +PHP_FUNCTION(array_replace_recursive) +{ + php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, 1); } /* }}} */ Index: ext/standard/basic_functions.c =================================================================== RCS file: /repository/php-src/ext/standard/basic_functions.c,v retrieving revision 1.725.2.31.2.19 diff -u -r1.725.2.31.2.19 basic_functions.c --- ext/standard/basic_functions.c 26 Jul 2006 08:57:44 -0000 1.725.2.31.2.19 +++ ext/standard/basic_functions.c 27 Jul 2006 07:34:07 -0000 @@ -458,6 +458,20 @@ ZEND_END_ARG_INFO() static +ZEND_BEGIN_ARG_INFO_EX(arginfo_array_replace, 0, 0, 2) + ZEND_ARG_INFO(0, arr1) /* ARRAY_INFO(0, arg, 0) */ + ZEND_ARG_INFO(0, arr2) /* ARRAY_INFO(0, arg, 0) */ + ZEND_ARG_INFO(0, ...) /* ARRAY_INFO(0, ..., 0) */ +ZEND_END_ARG_INFO() + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_array_replace_recursive, 0, 0, 2) + ZEND_ARG_INFO(0, arr1) /* ARRAY_INFO(0, arg, 0) */ + ZEND_ARG_INFO(0, arr2) /* ARRAY_INFO(0, arg, 0) */ + ZEND_ARG_INFO(0, ...) /* ARRAY_INFO(0, arg, 0) */ +ZEND_END_ARG_INFO() + +static ZEND_BEGIN_ARG_INFO_EX(arginfo_array_keys, 0, 0, 1) ZEND_ARG_INFO(0, arg) /* ARRAY_INFO(0, arg, 0) */ ZEND_ARG_INFO(0, search_value) @@ -3700,6 +3714,8 @@ PHP_FE(array_slice, arginfo_array_slice) PHP_FE(array_merge, arginfo_array_merge) PHP_FE(array_merge_recursive, arginfo_array_merge_recursive) + PHP_FE(array_replace, arginfo_array_replace) + PHP_FE(array_replace_recursive, arginfo_array_replace_recursive) PHP_FE(array_keys, arginfo_array_keys) PHP_FE(array_values, arginfo_array_values) PHP_FE(array_count_values, arginfo_array_count_values) Index: ext/standard/php_array.h =================================================================== RCS file: /repository/php-src/ext/standard/php_array.h,v retrieving revision 1.50.2.2.2.2 diff -u -r1.50.2.2.2.2 php_array.h --- ext/standard/php_array.h 15 Jul 2006 10:21:09 -0000 1.50.2.2.2.2 +++ ext/standard/php_array.h 27 Jul 2006 07:34:06 -0000 @@ -66,6 +66,8 @@ PHP_FUNCTION(array_slice); PHP_FUNCTION(array_merge); PHP_FUNCTION(array_merge_recursive); +PHP_FUNCTION(array_replace); +PHP_FUNCTION(array_replace_recursive); PHP_FUNCTION(array_keys); PHP_FUNCTION(array_values); PHP_FUNCTION(array_count_values);