diff options
| author | Johannes Schlüter <johannes@php.net> | 2008-07-31 20:18:17 +0000 |
|---|---|---|
| committer | Johannes Schlüter <johannes@php.net> | 2008-07-31 20:18:17 +0000 |
| commit | b9f7b21ec1c563c08ba431c952c48b556b30cdbe (patch) | |
| tree | 1d44fc7d94250ea3fdf4eb252ec97a945a5225af /ext/standard/array.c | |
| parent | 32508702493061b20f2ab332d290b6d05bac502f (diff) | |
| download | php-git-b9f7b21ec1c563c08ba431c952c48b556b30cdbe.tar.gz | |
MFH (DOC] Add array_replace/array_replace_recursive (Mett Wilmas)
Diffstat (limited to 'ext/standard/array.c')
| -rw-r--r-- | ext/standard/array.c | 103 |
1 files changed, 94 insertions, 9 deletions
diff --git a/ext/standard/array.c b/ext/standard/array.c index 456cae6a40..d1877876fb 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -2300,10 +2300,69 @@ PHPAPI int php_array_merge(HashTable *dest, HashTable *src, int recursive TSRMLS } /* }}} */ -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; + + for (zend_hash_internal_pointer_reset_ex(src, &pos); + zend_hash_get_current_data_ex(src, (void **)&src_entry, &pos) == SUCCESS; + zend_hash_move_forward_ex(src, &pos)) { + 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) == FAILURE || + Z_TYPE_PP(dest_entry) != IS_ARRAY) { + + Z_ADDREF_PP(src_entry); + zend_hash_update(dest, string_key, string_key_len, src_entry, sizeof(zval *), NULL); + + continue; + } + break; + + case HASH_KEY_IS_LONG: + if (Z_TYPE_PP(src_entry) != IS_ARRAY || + zend_hash_index_find(dest, num_key, (void **)&dest_entry) == FAILURE || + Z_TYPE_PP(dest_entry) != IS_ARRAY) { + + Z_ADDREF_PP(src_entry); + zend_hash_index_update(dest, num_key, src_entry, sizeof(zval *), NULL); + + continue; + } + break; + } + + if (Z_ARRVAL_PP(dest_entry)->nApplyCount > 1 || Z_ARRVAL_PP(src_entry)->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); + Z_ARRVAL_PP(dest_entry)->nApplyCount++; + Z_ARRVAL_PP(src_entry)->nApplyCount++; + + + if (!php_array_replace_recursive(Z_ARRVAL_PP(dest_entry), Z_ARRVAL_PP(src_entry) TSRMLS_CC)) { + Z_ARRVAL_PP(dest_entry)->nApplyCount--; + Z_ARRVAL_PP(src_entry)->nApplyCount--; + return 0; + } + Z_ARRVAL_PP(dest_entry)->nApplyCount--; + Z_ARRVAL_PP(src_entry)->nApplyCount--; + } + + 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; + int argc, i, params_ok = 1, init_size = 0; /* Get the argument count and check it */ argc = ZEND_NUM_ARGS(); @@ -2322,6 +2381,12 @@ static void php_array_merge_wrapper(INTERNAL_FUNCTION_PARAMETERS, int recursive) if (Z_TYPE_PP(args[i]) != IS_ARRAY) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument #%d is not an array", i + 1); params_ok = 0; + } else { + int num = zend_hash_num_elements(Z_ARRVAL_PP(args[i])); + + if (num > init_size) { + init_size = num; + } } } if (params_ok == 0) { @@ -2329,12 +2394,16 @@ static void php_array_merge_wrapper(INTERNAL_FUNCTION_PARAMETERS, int recursive) return; } - array_init(return_value); + array_init_size(return_value, init_size); - for (i=0; i<argc; i++) { - SEPARATE_ZVAL(args[i]); - convert_to_array_ex(args[i]); - php_array_merge(Z_ARRVAL_P(return_value), Z_ARRVAL_PP(args[i]), recursive TSRMLS_CC); + for (i = 0; i < argc; 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 */ + php_array_replace_recursive(Z_ARRVAL_P(return_value), Z_ARRVAL_PP(args[i]) TSRMLS_CC); + } else { + zend_hash_merge(Z_ARRVAL_P(return_value), Z_ARRVAL_PP(args[i]), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *), 1); + } } efree(args); @@ -2345,7 +2414,7 @@ static void php_array_merge_wrapper(INTERNAL_FUNCTION_PARAMETERS, int recursive) 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); } /* }}} */ @@ -2353,7 +2422,23 @@ PHP_FUNCTION(array_merge) 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); } /* }}} */ |
