为什么在引用值上调用函数(例如strlen,count等)这么慢?

Joh*_*ter 12 php performance reference pass-by-reference

我刚刚在PHP中发现了一些非常奇怪的东西.

如果我通过引用将变量传递给函数,然后在其上调用函数,那就非常慢.

如果循环遍历内部函数调用且变量很大,则它可能比通过值传递变量慢许多个数量级.

例:

<?php
function TestCount(&$aArray)
{
    $aArray = range(0, 100000);
    $fStartTime = microtime(true);

    for ($iIter = 0; $iIter < 1000; $iIter++)
    {
        $iCount = count($aArray);
    }

    $fTaken = microtime(true) - $fStartTime;

    print "took $fTaken seconds\n";
}

$aArray = array();
TestCount($aArray);
?>
Run Code Online (Sandbox Code Playgroud)

这在我的机器上运行大约需要20秒(在PHP 5.3上).

但是,如果我将函数更改为按值传递(即function TestCount($aArray)代替function TestCount(&$aArray)),则它会在大约2毫秒内运行 - 实际上要快10,000倍!

对于其他内置函数(例如strlen用户定义的函数)也是如此.

这是怎么回事?

Joh*_*ter 13

我发现2005年的错误报告正好描述了这个问题:http://bugs.php.net/bug.php?id = 34540

所以问题似乎是当将引用的值传递给不接受引用的函数时,PHP需要复制它.

这个测试代码可以证明这一点:

<?php
function CalledFunc(&$aData)
{
    // Do nothing
}

function TestFunc(&$aArray)
{
    $aArray = range(0, 100000);
    $fStartTime = microtime(true);

    for ($iIter = 0; $iIter < 1000; $iIter++)
    {
        CalledFunc($aArray);
    }

    $fTaken = microtime(true) - $fStartTime;

    print "took $fTaken seconds\n";
}

$aArray = array();
TestFunc($sData);
?>
Run Code Online (Sandbox Code Playgroud)

这很快就会运行,但是如果你改变了function CalledFunc(&$aData),function CalledFunc($aData)你会看到类似的减慢速度count.

这是相当令人担忧的,因为我已经编写PHP很长一段时间了,我不知道这个问题.

幸运的是,有一个简单的解决方法适用于许多情况 - 在循环中使用临时局部变量,并在最后复制到引用变量.

  • 是的,但我认为行为(PHP克隆数组)是正确和合理的,因为我们不希望接受数组的函数作为值来修改原始数组(如果没有克隆).没有它就活不下去.也许我们作为程序员可以做的就是关注这个场景并避免它. (3认同)