代码之家  ›  专栏  ›  技术社区  ›  James McMahon

在php(>=5.0)中,按引用传递是否更快?

  •  62
  • James McMahon  · 技术社区  · 16 年前

    在PHP中,函数参数可以通过引用传递,方法是在函数声明中的参数前面加上一个和号,如下所示:

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

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

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

    但是,我想知道copy-on-write逻辑是否在pass-by引用时短路,以及这是否对性能有任何影响。

    埃塔:可以肯定的是,我认为它不会更快,我很清楚这不是参考文献的目的。所以我认为我自己的猜测是相当好的,我只是在寻找一个真正知道引擎盖下肯定发生了什么的人的答案。在五年的PHP开发中,我总是发现很难从阅读源代码中获得关于PHP内部结构的高质量信息。

    8 回复  |  直到 7 年前
        1
  •  33
  •   hakre    10 年前

    Zend引擎使用copy-on-write,当您自己使用引用时,它会增加一些额外的开销。只能找到 this mention 但在写作的时候, the manual 包含其他链接。

    (编辑)手册第页 Objects and references 包含关于对象变量与引用之间的区别的更多信息。

        2
  •  69
  •   Svish    13 年前

    在调用字符串为20KB的函数的100000次迭代的测试中,结果是:

    只读取/使用参数的函数

    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. 如果函数更改了传递的变量的值,则出于实际目的,它与传递引用的值相同,而不是按值。

        3
  •  27
  •   Petah    13 年前

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

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

    以下是我的结果: 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) {
    }
    
        4
  •  6
  •   Vladimir Fesko    13 年前

    我已经尝试了将10k字节字符串传递给两个相同函数的值和引用。一个按值接受参数,另一个按引用接受参数。它们是常见的函数-接受参数,进行简单的处理并返回一个值。我同时打了10万次电话,发现引用并不是为了提高性能而设计的——引用的利润接近4-5%,只有当字符串足够大时才会增长(10万次及更长时间,这就提高了6-7%)。所以,我的结论是 不要用参考资料来提高工作效率,这是不适合的。

    我使用了5.3.1版的PHP

        5
  •  4
  •   Greg    16 年前

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

    编辑:找不到它说的地方,但它在那里!

        6
  •  1
  •   Melsi    10 年前

    没有什么比测试代码更好的了

    <?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;
    ?>
    

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

    否则,“按引用”和“按值”之间没有真正的区别,编译器足够聪明,如果不需要的话,每次都不创建新的副本。

        7
  •  0
  •   Bob Ray    7 年前

    我试着用一个基于我正在研究的项目的真实例子作为基准。和往常一样,这些差异微不足道,但结果有些出人意料。对于我看到的大多数基准,被调用的函数实际上并没有改变传入的值。我对它执行了一个简单的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更快,但可能不会更快。)

        8
  •  -2
  •   Michał Niedźwiedzki    16 年前

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