PHP函数源码之array_merge分析

在使用array_merge时是需要注意键的类型的,对于string 的key  和 数字key的处理方式是有区别的,虽然应用没问题, 但是偶尔写的时候总有点对预期结果不踏实,所以我们还是从底层来分析下,这样在用时候也就底气十足了

PHP_FUNCTION(array_merge)
{
	php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 0);
}
注意传入的参数, recursive=0, replace=0  ( 不递归merge,数字索引不替换 )

static void php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAMETERS, int recursive, int replace) /* {{{ */
{
	zval ***args = NULL;
	int argc, i, init_size = 0;

	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &argc) == FAILURE) {
		return;
	}

	for (i = 0; i < argc; i++) {
		if (Z_TYPE_PP(args[i]) != IS_ARRAY) {
			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument #%d is not an array", i + 1);
			efree(args);
			RETURN_NULL();
		} else {
			int num = zend_hash_num_elements(Z_ARRVAL_PP(args[i]));

			/* 使用元素最多的数组的大小作为init_size的大小 */  
			if (num > init_size) {
				init_size = num;
			}
		}
	}

	array_init_size(return_value, init_size);

	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);
}
这里进入php_array_merge  根据传入的参数 recursive=0 省略多余分支,基本流程可归结为

switch (zend_hash_get_current_key_ex(src, &string_key, &string_key_len, &num_key, 0, &pos)){  
    case HASH_KEY_IS_STRING:  
        Z_ADDREF_PP(src_entry);  
        zend_hash_update(dest, string_key, string_key_len, src_entry, sizeof(zval *), NULL);  
    break;  
   
    case HASH_KEY_IS_LONG:  
        Z_ADDREF_PP(src_entry);  
        zend_hash_next_index_insert(dest, src_entry, sizeof(zval *), NULL);  
    break;  
} 
上述代码表明:

对于字符串索引,会更新字符串索引的值,其结果就是参数靠后数组的值会覆盖靠前的数组的值。

而对于数字型索引,PHP执行的zend_hash_next_index_insert操作,也就是插入一个新的元素,这同时也更改了键(例如原来的key=2, array_merge之后,可能变成了0)。

这样我们在理解下面的脚本时就没什么疑问了

$array1  = array( 'key'=>'one_key_a', 10  =>  'zero_a' ,  2  =>  'two_a' ,  3  =>  'three_a' );
$array2  = array( 'key'=>'one_key_b', 1  =>  'one_b' ,  3  =>  'three_b' ,  4  =>  'four_b' );

var_dump(array_merge($array1, $array2), ($array1 + $array2), $array1, $array2);
结果:

array (size=7)
  'key' => string 'one_key_b' (length=9)
  0 => string 'zero_a' (length=6)
  1 => string 'two_a' (length=5)
  2 => string 'three_a' (length=7)
  3 => string 'one_b' (length=5)
  4 => string 'three_b' (length=7)
  5 => string 'four_b' (length=6)
array (size=6)
  'key' => string 'one_key_a' (length=9)
  10 => string 'zero_a' (length=6)
  2 => string 'two_a' (length=5)
  3 => string 'three_a' (length=7)
  1 => string 'one_b' (length=5)
  4 => string 'four_b' (length=6)
array (size=4)
  'key' => string 'one_key_a' (length=9)
  10 => string 'zero_a' (length=6)
  2 => string 'two_a' (length=5)
  3 => string 'three_a' (length=7)
array (size=4)
  'key' => string 'one_key_b' (length=9)
  1 => string 'one_b' (length=5)
  3 => string 'three_b' (length=7)
  4 => string 'four_b' (length=6)



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值