PHP函数array_replace(),为什么参数是通过引用传递的?

5
PHP.net上array_replace()函数的函数签名表明,数组将以引用方式传递。与按值传递相比,这种方法的原因/优点是什么,因为要获得预期的结果,必须将完成的数组返回给变量。只是为了明确,我能够在手册中复制结果,所以这不是关于如何使用此函数的问题。
以下是来自php.net的函数签名和示例:
来源:http://ca3.php.net/manual/en/function.array-replace.php
array array_replace ( array &$array , array &$array1 [, array &$... ] )

示例代码:
$base = array("orange", "banana", "apple", "raspberry");
$replacements = array(0 => "pineapple", 4 => "cherry");
$replacements2 = array(0 => "grape");

$basket = array_replace($base, $replacements, $replacements2);
print_r($basket);

上面的例子将输出:
Array
(
    [0] => grape
    [1] => banana
    [2] => apple
    [3] => raspberry
    [4] => cherry
)

2
原因非常简单:http://me.veekun.com/blog/2012/04/09/php-a-fractal-of-bad-design/ :) - biziclop
1
@biziclop 那篇文章是一篇非常长的抱怨。他非常坦率地表示不喜欢PHP,所以当然这篇文章对它有负面偏见。但这并不意味着他是100%正确的。 - WWW
顺便提一下,“array_replace”的文档页面最近已经更新了 - 我们所讨论的错误现在已经消失了。所以我想我们终究可以让这个世界变得更好。 - raina77ow
4个回答

4

你可能意思是使用引用将数据合并到 PHP 的 array_replace() 函数中 - array_merge() 签名 是官方无引用的。 - raina77ow
@Crontab 感谢您的回答。我现在明白了。 - Jon Lyles
人们是否因为熟悉PHP的内部工作原理而对此进行了投票,所以你同意整个memcmp的事情?我不相信... - goat
@rambocoder 你有阅读代码链接吗?它们直接指向PHP的源代码(而memcmp()链接指向GNU的libc手册),我不确定还有哪些参考资料更可靠... - WWW
抱歉,我的评论表达不够清晰。我感觉你的回答暗示了PHP必须以这种方式实现。例如,如果有性能原因导致他们这样做,那么我认为这将是更好的答案。但目前它只谈论源代码,显然它可以正常工作,但并没有回答为什么这样做。 - goat
1
@rambocoder PHP源代码中缺乏足够的注释来解释他们选择这样做的原因。我认为我不应该因为没有给Rasmus打电话请他解释而被评为负分。 - WWW

3
好的,重点是 _zend_hash_merge 函数不仅被array_merge使用,还被+运算符(当操作数都是数组时)使用。

虽然在处理过程中存在一些差异,但实际上这些差异都不能归因于要求的差异:据我所知,没有人会将+写成&$arr + &$arr,那根本没有意义。

所以我认为这只是文档中的错误。

但是即使不分析PHP内部代码的深渊,也可以得出这个结论。)请记住,当我们传递一个可以被更改的数组时,我们使用&$array表示法——例如,array_splice()签名。而且(这很容易检查),array_replace不会改变它的参数 - 至少目前是这样。

更新:好吧,现在我很生气。如果某个PHP开发者,上帝保佑他/她的灵魂,实际认为这不是文档中的错误,那么让他/她解释一下为什么这个:

array_pop(array('a' => 1));

...触发了致命错误(只有变量可以通过引用传递),并且这个...

array_replace(array('a' => 1), array('b' => 2));

如果没有发生任何事情,那么就会自动工作。

那么现在PHP中是否有两种引用类型呢?


我也认为这是一个错误,因此我提交了一个错误报告,并从某人那里收到了答复,说这不是一个错误,因为该函数的工作方式与文档中描述的一样。但文档还说:“您可以通过引用将变量传递给函数,以便函数可以修改变量”。 - Jon Lyles
2
更新了答案。太神奇了:每次我认为 PHP 支持社区不会再让我惊讶,它总是能做到。 - raina77ow
1
PHP并不总是会抱怨这个。例如current(array(1));但是...我认为current()只是文档错误地标记为需要一个引用。 - goat

1

假设:

由于按值传递涉及复制数组,我猜通过引用传递它们会更快。

测试一下:

<?php 

function ref(array &$array) {
    for($i = 0; $i < count($array); $i++) {
        $array[$i] == 'foo'; //just accessing
    }
}

function val(array $array) {
    for($i = 0; $i < count($array); $i++) {
        $array[$i] == 'foo'; //just accessing
    }
}


//create large array
$array = array();
for($i = 0; $i < 100; $i++) {
    $array[] = $i;
}


echo "Pass by reference\n";
$t1 = microtime(true);
for($i = 0; $i < 10000; $i++) {
    ref($array);
}
$t2 = microtime(true);
echo $t2 - $t1 . "s\n\n";

echo "Pass by value\n";
$t1 = microtime(true);
for($i = 0; $i < 10000; $i++) {
    val($array);
}
$t2 = microtime(true);
echo $t2 - $t1 . "s\n\n";

输出:

Pass by reference
8.3282010555267s

Pass by value
1.4845979213715s

结论:

显然这不是出于性能原因。


尝试调用ref(array('a' => 1))val(array('a' => 1))。看看小小的&符号会带来什么不同? - raina77ow
@raina77ow - 实际上,传递引用似乎会更慢(请查看测试结果),因此整个“它是为了性能”的想法是错误的。 - Roman

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接