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

后端 未结 2 679
后悔当初
后悔当初 2020-11-30 11:36

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

相关标签:
2条回答
  • 2020-11-30 12:14

    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 seconds\n";
    }
    
    $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.

    0 讨论(0)
  • 2020-11-30 12:18

    So, taking your answer already given, you can partially avoid this issue by forcing the copy before iterative work (Copying back afterward if the data is changed).

    <?php
    function TestCountNon($aArray)
    {
        $aArray = range(0, 100000);
        $fStartTime = microtime(true);
        for ($iIter = 0; $iIter < 1000; $iIter++)
        {
            $iCount = count($aArray);
        }
        $fTaken = microtime(true) - $fStartTime;
    
        print "Non took $fTaken seconds\n<br>";
    }
    
    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<br>";
    }
    
    function TestCountA(&$aArray)
    {
        $aArray = range(0, 100000);
        $fStartTime = microtime(true);
        $bArray = $aArray;
        for ($iIter = 0; $iIter < 1000; $iIter++)
        {
            $iCount = count($bArray);
        }
        $aArray = $bArray;
        $fTaken = microtime(true) - $fStartTime;
    
        print "A took $fTaken seconds\n<br>";
    }
    
    $nonArray = array();
    TestCountNon($nonArray);
    
    $aArray = array();
    TestCount($aArray);
    
    $bArray = array();
    TestCountA($bArray);
    ?>
    

    Results are:

    Non took 0.00090217590332031 seconds 
    took 17.676940917969 seconds 
    A took 0.04144287109375 seconds 
    

    Not quite as good, but a damn lot better.

    0 讨论(0)
提交回复
热议问题