在PHP(> = 5.0)中,更快地通过引用传递?

时间:2008-10-07 13:04:41

标签: php performance pass-by-reference

在PHP中,函数参数可以通过在函数声明中的参数前加一个&符号来传递,如下所示:

function foo(&$bar)
{
    // ...
}

现在,我知道这是 not 旨在提高性能,但允许函数更改通常超出其范围的变量。

相反,PHP似乎使用Copy On Write来避免复制对象(也可能是数组),直到它们被更改为止。因此,对于不更改其参数的函数,效果应与通过引用传递它们的效果相同。

但是,我想知道Copy On Write逻辑是否可能在传递引用时短路,以及是否会对性能产生任何影响。

ETA:可以肯定的是,我认为它并不快,而且我很清楚这不是引用的内容。所以我认为我自己的猜测非常好,我只是想找一个真正知道发生在幕后的人的回答。在PHP开发的五年中,我总是发现很难从阅读源代码中获得有关PHP内部的高质量信息。

9 个答案:

答案 0 :(得分:70)

在一次使用字符串20 kB调用函数的100 000次迭代测试中,结果如下:

只读取/使用参数

的函数
pass by value:      0.12065005 seconds
pass by reference:  1.52171397 seconds

写入/更改参数

的功能
pass by value:      1.52223396 seconds
pass by reference:  1.52388787 seconds

结论

  1. 按值传递参数总是更快

  2. 如果函数更改传递的变量的值,则实际用途与按引用传递的值相同而不是按值传递

答案 1 :(得分:33)

Zend引擎使用copy-on-write,当你自己使用引用时,会产生一些额外的开销。但在撰写本文时只能找到this mentionthe manual中的评论包含其他链接。

(编辑)Objects and references上的手册页包含有关对象变量与参考文献有何不同的更多信息。

答案 2 :(得分:27)

我对此进行了一些测试,因为我不确定给出的答案。

我的结果表明,通过引用IS传递大型数组或字符串的速度要快得多。

以下是我的结果: Benchmark

Y轴(运行)是在1秒内调用函数的次数* 10

对于每个函数/变量

重复测试8次

以下是我使用的变量:

$large_array = array_fill(PHP_INT_MAX / 2, 1000, 'a');
$small_array = array('this', 'is', 'a', 'small', 'array');
$large_object = (object)$large_array;
$large_string = str_repeat('a', 100000);
$small_string = 'this is a small string';
$value = PHP_INT_MAX / 2;

这些是功能:

function pass_by_ref(&$var) {
}

function pass_by_val($var) {
}

答案 3 :(得分:6)

我已经尝试了将10k字节字符串的值和引用传递给两个相同的函数。一个通过值进行参数,第二个通过引用进行。它们是常用函数 - 接受参数,进行简单处理并返回值。我做了两万次调用,并发现引用并不是为了提高性能 - 参考利润接近4-5%,只有当字符串变得足够大时才会增长(100k及更长时间,提高了6-7%) 。所以,我的结论是不要使用引用来提高性能,这个东西不是为了那个。

我使用的是PHP Version 5.3.1

答案 4 :(得分:4)

我很确定不,它不会更快。 此外,它在手册中特别指出不要尝试使用引用来提高性能。

编辑:找不到它的位置,但它就在那里!

答案 5 :(得分:1)

没有比测试代码更好的了解

<?PHP
$r = array();

for($i=0; $i<500;$i++){
$r[]=5;
}

function a($r){
$r[0]=1;
}
function b(&$r){
$r[0]=1;
}

$start = microtime(true);
for($i=0;$i<9999;$i++){
  //a($r);
  b($r);
}
$end = microtime(true);

echo $end-$start;
?>

最终结果!数组越大(或调用次数越多),差异越大。因此,在这种情况下,通过引用调用更快,因为函数内部的值已更改。

否则&#34;参考&#34;之间没有真正的区别。和&#34;按值&#34;,编译器足够聪明,如果不需要,每次都不创建新副本。

答案 6 :(得分:0)

我尝试使用基于我正在处理的项目的真实示例对此进行基准测试。与往常一样,差异是微不足道的,但结果有些出乎意料。对于我见过的大多数基准测试,被调用的函数实际上并没有改变传入的值。我在它上面执行了一个简单的str_replace()。

**Pass by Value Test Code:**

$originalString=''; // 1000 pseudo-random digits

function replace($string) {
    return str_replace('1', 'x',$string);
}
$output = '';
/* set start time */
$mtime = microtime();
$mtime = explode(" ", $mtime);
$mtime = $mtime[1] + $mtime[0];
$tstart = $mtime;
set_time_limit(0);

for ($i = 0; $i < 10; $i++ ) {
    for ($j = 0; $j < 1000000; $j++) {
        $string = $originalString;
        $string = replace($string);
    }
}

/* report how long it took */
$mtime = microtime();
$mtime = explode(" ", $mtime);
$mtime = $mtime[1] + $mtime[0];
$tend = $mtime;
$totalTime = ($tend - $tstart);
$totalTime = sprintf("%2.4f s", $totalTime);
$output .= "\n" . 'Total Time' .
    ': ' . $totalTime;
$output .= "\n" . $string;
echo $output;

通过参考测试代码

除了

之外
function replace(&$string) {
    $string = str_replace('1', 'x',$string);
}
/* ... */
replace($string);

以秒为单位的结果(1000万次迭代):

PHP 5
    Value:     14.1007
    Reference: 11.5564

PHP 7
    Value:     3.0799
    Reference: 2.9489

每个函数调用的差异只有几分之一毫秒,但对于这个用例,PHP 5和PHP 7中的引用传递速度更快。

(注意:PHP 7测试是在更快的机器上执行的 - PHP 7更快,但可能没那么快。)

答案 7 :(得分:0)

很简单,不需要测试任何东西。 取决于用例。

对于少量参数,按值传递将始终比参考值更快。这取决于体系结构允许通过寄存器(ABI)传递多少个变量。

例如,x64将允许您将4个值(每个64位)通过寄存器传递。 https://en.wikipedia.org/wiki/X86_calling_conventions

这是因为您不必取消引用指针,只需直接使用value。

如果需要传递的数据大于ABI,则其余值将进入堆栈。 在这种情况下,数组或对象(例如,它是一个类,或者是一个结构+头文件)总是会被引用更快。

这是因为引用只是指向数据的指针(不是数据本身),其大小固定为32位或64位,具体取决于计算机。该指针将适合一个CPU寄存器。

PHP用C / C ++编写,所以我希望表现相同。

答案 8 :(得分:-2)

无需添加&amp;传递对象时的运算符。在PHP中,5+对象无论如何都通过引用传递。