summaryrefslogtreecommitdiff
path: root/ext/standard/array.c
diff options
context:
space:
mode:
authorJohannes Schlüter <johannes@php.net>2008-07-31 20:18:17 +0000
committerJohannes Schlüter <johannes@php.net>2008-07-31 20:18:17 +0000
commitb9f7b21ec1c563c08ba431c952c48b556b30cdbe (patch)
tree1d44fc7d94250ea3fdf4eb252ec97a945a5225af /ext/standard/array.c
parent32508702493061b20f2ab332d290b6d05bac502f (diff)
downloadphp-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.c103
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);
}
/* }}} */