johannes Thu Jul 31 20:18:17 2008 UTC
Added files: (Branch: PHP_5_3)
/php-src/ext/standard/tests array_replace.phpt
Modified files:
/php-src/ext/standard array.c basic_functions.c php_array.h
Log:
MFH (DOC] Add array_replace/array_replace_recursive (Mett Wilmas)
http://cvs.php.net/viewvc.cgi/php-src/ext/standard/array.c?r1=1.308.2.21.2.37.2.37&r2=1.308.2.21.2.37.2.38&diff_format=u
Index: php-src/ext/standard/array.c
diff -u php-src/ext/standard/array.c:1.308.2.21.2.37.2.37
php-src/ext/standard/array.c:1.308.2.21.2.37.2.38
--- php-src/ext/standard/array.c:1.308.2.21.2.37.2.37 Thu Jul 24 03:07:22 2008
+++ php-src/ext/standard/array.c Thu Jul 31 20:18:17 2008
@@ -21,7 +21,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: array.c,v 1.308.2.21.2.37.2.37 2008/07/24 03:07:22 felipe Exp $ */
+/* $Id: array.c,v 1.308.2.21.2.37.2.38 2008/07/31 20:18:17 johannes Exp $ */
#include "php.h"
#include "php_ini.h"
@@ -2300,10 +2300,69 @@
}
/* }}} */
-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 @@
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 @@
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 @@
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 @@
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);
}
/* }}} */
http://cvs.php.net/viewvc.cgi/php-src/ext/standard/basic_functions.c?r1=1.725.2.31.2.64.2.42&r2=1.725.2.31.2.64.2.43&diff_format=u
Index: php-src/ext/standard/basic_functions.c
diff -u php-src/ext/standard/basic_functions.c:1.725.2.31.2.64.2.42
php-src/ext/standard/basic_functions.c:1.725.2.31.2.64.2.43
--- php-src/ext/standard/basic_functions.c:1.725.2.31.2.64.2.42 Tue Jul 29
17:28:41 2008
+++ php-src/ext/standard/basic_functions.c Thu Jul 31 20:18:17 2008
@@ -18,7 +18,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: basic_functions.c,v 1.725.2.31.2.64.2.42 2008/07/29 17:28:41 pajoye
Exp $ */
+/* $Id: basic_functions.c,v 1.725.2.31.2.64.2.43 2008/07/31 20:18:17 johannes
Exp $ */
#include "php.h"
#include "php_streams.h"
@@ -461,6 +461,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)
@@ -3696,6 +3710,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)
http://cvs.php.net/viewvc.cgi/php-src/ext/standard/php_array.h?r1=1.50.2.2.2.3.2.2&r2=1.50.2.2.2.3.2.3&diff_format=u
Index: php-src/ext/standard/php_array.h
diff -u php-src/ext/standard/php_array.h:1.50.2.2.2.3.2.2
php-src/ext/standard/php_array.h:1.50.2.2.2.3.2.3
--- php-src/ext/standard/php_array.h:1.50.2.2.2.3.2.2 Mon Dec 31 07:17:15 2007
+++ php-src/ext/standard/php_array.h Thu Jul 31 20:18:17 2008
@@ -19,7 +19,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: php_array.h,v 1.50.2.2.2.3.2.2 2007/12/31 07:17:15 sebastian Exp $ */
+/* $Id: php_array.h,v 1.50.2.2.2.3.2.3 2008/07/31 20:18:17 johannes Exp $ */
#ifndef PHP_ARRAY_H
#define PHP_ARRAY_H
@@ -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);
@@ -102,6 +104,7 @@
PHPAPI HashTable* php_splice(HashTable *, int, int, zval ***, int, HashTable
**);
PHPAPI int php_array_merge(HashTable *dest, HashTable *src, int recursive
TSRMLS_DC);
+PHPAPI int php_array_replace_recursive(HashTable *dest, HashTable *src
TSRMLS_DC);
PHPAPI int php_multisort_compare(const void *a, const void *b TSRMLS_DC);
#define PHP_SORT_REGULAR 0
http://cvs.php.net/viewvc.cgi/php-src/ext/standard/tests/array_replace.phpt?view=markup&rev=1.1
Index: php-src/ext/standard/tests/array_replace.phpt
+++ php-src/ext/standard/tests/array_replace.phpt
--TEST--
Test array_replace and array_replace_recursive
--FILE--
<?php
$array1 = array(
0 => 'dontclobber',
'1' => 'unclobbered',
'test2' => 0.0,
'test3' => array(
'testarray2' => true,
1 => array(
'testsubarray1' => 'dontclobber2',
'testsubarray2' => 'dontclobber3',
),
),
);
$array2 = array(
1 => 'clobbered',
'test3' => array(
'testarray2' => false,
),
'test4' => array(
'clobbered3' => array(0, 1, 2),
),
);
$array3 = array(array(array(array())));
$array4 = array();
$array4[] = &$array4;
echo " -- Testing array_replace() --\n";
$data = array_replace($array1, $array2);
var_dump($data);
echo " -- Testing array_replace_recursive() --\n";
$data = array_replace_recursive($array1, $array2);
var_dump($data);
echo " -- Testing array_replace_recursive() w/ endless recusrsion --\n";
$data = array_replace_recursive($array3, $array4);
var_dump($data);
?>
--EXPECTF--
-- Testing array_replace() --
array(5) {
[0]=>
unicode(11) "dontclobber"
[1]=>
unicode(9) "clobbered"
[u"test2"]=>
float(0)
[u"test3"]=>
array(1) {
[u"testarray2"]=>
bool(false)
}
[u"test4"]=>
array(1) {
[u"clobbered3"]=>
array(3) {
[0]=>
int(0)
[1]=>
int(1)
[2]=>
int(2)
}
}
}
-- Testing array_replace_recursive() --
array(5) {
[0]=>
unicode(11) "dontclobber"
[1]=>
unicode(9) "clobbered"
[u"test2"]=>
float(0)
[u"test3"]=>
array(2) {
[u"testarray2"]=>
bool(false)
[1]=>
array(2) {
[u"testsubarray1"]=>
unicode(12) "dontclobber2"
[u"testsubarray2"]=>
unicode(12) "dontclobber3"
}
}
[u"test4"]=>
array(1) {
[u"clobbered3"]=>
array(3) {
[0]=>
int(0)
[1]=>
int(1)
[2]=>
int(2)
}
}
}
-- Testing array_replace_recursive() w/ endless recusrsion --
Warning: array_replace_recursive(): recursion detected in %s on line %d
array(1) {
[0]=>
array(1) {
[0]=>
array(1) {
[0]=>
array(0) {
}
}
}
}
--
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php