Search code examples
phparraysoptimizationphp-internals

Does PHP optimize function arguments of array type, not explicitly passed by reference, when they are not modified?


Would the PHP engine optimize the second example to pass the $arr by reference?

function test1(array &$arr)
{
    $arr[] = 123;

    echo $arr[0];
}

function test2(array $arr)
{
    echo $arr[0];
}

Solution

  • PHP uses a mechanism called copy-on-write to avoid exactly the excessive copying of variables as long as it's unnecessary to do so. So even in your test2() example $array is not copied at all. If you'd modified $array inside the function, PHP would have copied the variable to allow modification. A detailed explanation of this mechanism can be found in the "Memory Management" chapter of the "PHP Internals Book". The following quote is from the "Reference-counting and copy-on-write" section:

    If you think about the above for a bit, you’ll come to the conclusion that PHP must be doing an awful lot of copying. Every time you pass something to a function the value needs to be copied. This may not be particularly problematic for an integer or a double, but imagine passing an array with ten million elements to a function. Copying millions of elements on every call would be prohibitively slow.

    To avoid doing so, PHP employs the copy-on-write paradigm: A zval can be shared by multiple variables/functions/etc as long as it’s only read from and not modified. If one of the holders wants to modify it, the zval needs to be copied before applying any changes.

    The following two articles provide even more insight into this topic (both written by PHP core developers):

    The first one even explains why using references just for performance reasons is most often a bad idea:

    Another reason people use reference is since they think it makes the code faster. But this is wrong. It is even worse: References mostly make the code slower!

    Yes, references often make the code slower - Sorry, I just had to repeat this to make it clear.

    And the second one shows why objects are not really passed by reference in PHP5+.