Skip to content
Advertisement

Why is calling a function (such as strlen, count etc) on a referenced value so slow?

I’ve just found something very strange in PHP.

If I pass in a variable to a function by reference, and then call a function on it, it’s incredibly slow.

If you loop over the inner function call and the variable is large it can be many orders of magnitude slower than if the variable is passed by value.

Example:

<?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 secondsn";
}

$aArray = array();
TestCount($aArray);
?>

This consistently takes about 20 seconds to run on my machine (on PHP 5.3).

But if I change the function to pass by value (ie function TestCount($aArray) instead of function TestCount(&$aArray)), then it runs in about 2ms – literally 10,000 times faster!

The same is true for other built-in functions such as strlen, and for user-defined functions.

What’s going on?

Advertisement

Answer

I found a bug report from 2005 that describes exactly this issue: http://bugs.php.net/bug.php?id=34540

So the problem seems to be that when passing a referenced value to a function that doesn’t accept a reference, PHP needs to copy it.

This can be demonstrated with this test code:

<?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 secondsn";
}

$aArray = array();
TestFunc($sData);
?>

This runs quickly, but if you change function CalledFunc(&$aData) to function CalledFunc($aData) you’ll see a similar slow-down to the count example.

This is rather worrying, since I’ve been coding PHP for quite a while and I had no idea about this issue.

Fortunately there’s a simple workaround that is applicable in many cases – use a temporary local variable inside the loop, and copy to the reference variable at the end.

User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement