Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP Performance : Copy vs. Reference

Hey there. Today I wrote a small benchmark script to compare performance of copying variables vs. creating references to them. I was expecting, that creating references to large arrays for example would be significantly slower than copying the whole array. Here is my benchmark code:

<?php
    $array = array();

    for($i=0; $i<100000; $i++) {
        $array[] = mt_rand();
    }

    function recursiveCopy($array, $count) {
        if($count === 1000)
            return;

        $foo = $array;
        recursiveCopy($array, $count+1);
    }

    function recursiveReference($array, $count) {
        if($count === 1000)
            return;

        $foo = &$array;
        recursiveReference($array, $count+1);
    }

    $time = microtime(1);
    recursiveCopy($array, 0);
    $copyTime = (microtime(1) - $time);
    echo "Took " . $copyTime . "s \n";


    $time = microtime(1);
    recursiveReference($array, 0);
    $referenceTime = (microtime(1) - $time);
    echo "Took " . $referenceTime . "s \n";

    echo "Reference / Copy: " . ($referenceTime / $copyTime);

The actual result I got was, that recursiveReference took about 20 times (!) as long as recursiveCopy.

Can somebody explain this PHP behaviour?

like image 359
fresskoma Avatar asked Oct 28 '10 13:10

fresskoma


People also ask

Is passing by reference faster PHP?

In fact, in most scenarios passing by value is faster and less memory intensive than passing by reference. The Zend Engine, PHP's core, uses a copy-on-write optimization mechanism that does not create a copy of a variable until it is modified.

Does PHP copy by reference?

TL;DR: PHP supports both pass by value and pass by reference. References are declared using an ampersand ( & ); this is very similar to how C++ does it.

Does PHP pass arrays by reference or value?

With regards to your first question, the array is passed by reference UNLESS it is modified within the method / function you're calling. If you attempt to modify the array within the method / function, a copy of it is made first, and then only the copy is modified.

What happens when there is argument mismatch during function call in PHP?

function foo(&$arg) { } $var = 'str'; foo($var); Do you know what horrible things happen under the hood in the PHP 5 engine? In PHP 5, whenever there is a reference mismatch, the engine is forced to duplicate the variable before passing it as an argument to a function.


2 Answers

PHP will very likely implement copy-on-write for its arrays, meaning when you "copy" an array, PHP doesn't do all the work of physically copying the memory until you modify one of the copies and your variables can no longer reference the same internal representation.

Your benchmarking is therefore fundamentally flawed, as your recursiveCopy function doesn't actually copy the object; if it did, you would run out of memory very quickly.

Try this: By assigning to an element of the array you force PHP to actually make a copy. You'll find you run out of memory pretty quickly as none of the copies go out of scope (and aren't garbage collected) until the recursive function reaches its maximum depth.

function recursiveCopy($array, $count) {
    if($count === 1000)
        return;

    $foo = $array;
    $foo[9492] = 3; // Force PHP to copy the array
    recursiveCopy($array, $count+1);
}
like image 67
meagar Avatar answered Sep 30 '22 08:09

meagar


in recursiveReference you're calling recursiveCopy... this doesn't make any sense, in this case you're calling recursiveReference just once. correct your code, rund the benchmark again and come back with your new results.

in addition, i don't think it's useful for a benchmark to do this recursively. a better solution would be to call a function 1000 times in a loop - once with the array directly and one with a reference to that array.

like image 29
oezi Avatar answered Sep 30 '22 08:09

oezi