PHP performance: copy by reference

Hey there. Today I wrote a small landmark script to compare the performance of copying variables and linking to them. I expected that creating links to large arrays, for example, would be significantly slower than copying the entire array. Here is my test 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 (!) Until recursiveCopy.

Can anyone explain this behavior to PHP?

+7
reference benchmarking php php-internals
source share
6 answers

PHP most likely implements copy-on-write for its arrays, that is, when you "copy" an array, PHP does not do all the work of physically copying memory until you change one of the copies and your variables no longer will be able to refer to the same internal representation.

Thus, your benchmarking is a fundamental flaw, since your recursiveCopy function does not actually copy the object; if this happened, you would not have enough memory very quickly.

Try the following: assigning an element to an array will force PHP to make a copy. You will find that you are running out of memory pretty quickly, since none of the copies goes out of scope (and does not collect garbage) 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); } 
+16
source share

in recursiveReference you call recursiveCopy ... it makes no sense, in this case you call recursiveReference only once. correct your code, run the test again and come back with new results.

Also, I don't think it is useful for a test to do this recursively. the best solution would be to call the function 1000 times in a loop - once with the array directly and one with a reference to this array.

+3
source share

You do not need (and therefore should not) assign or pass variables by reference only for performance reasons. PHP does such optimizations automatically.

The completed test is erroneous due to these automatic optimizations. Instead, performed the following test:

 <?php for($i=0; $i<100000; $i++) { $array[] = mt_rand(); } $time = microtime(1); for($i=0; $i<1000; $i++) { $copy = $array; unset($copy); } $duration = microtime(1) - $time; echo "Normal Assignment and don't write: $duration<br />\n"; $time = microtime(1); for($i=0; $i<1000; $i++) { $copy =& $array; unset($copy); } $duration = microtime(1) - $time; echo "Assignment by Reference and don't write: $duration<br />\n"; $time = microtime(1); for($i=0; $i<1000; $i++) { $copy = $array; $copy[0] = 0; unset($copy); } $duration = microtime(1) - $time; echo "Normal Assignment and write: $duration<br />\n"; $time = microtime(1); for($i=0; $i<1000; $i++) { $copy =& $array; $copy[0] = 0; unset($copy); } $duration = microtime(1) - $time; echo "Assignment by Reference and write: $duration<br />\n"; ?> 

This was the result:

 //Normal Assignment without write: 0.00023698806762695 //Assignment by Reference without write: 0.00023508071899414 //Normal Assignment with write: 21.302103042603 //Assignment by Reference with write: 0.00030708312988281 

As you can see, there is no significant difference in performance when assigning by reference, until you actually write to the copy, that is, when there is also a functional difference.

+3
source share

Generally speaking, in PHP, calling by reference is not what you do for performance reasons; this is what you do for functional reasons, i.e. because you really want the variable referenced to be updated.

Unless you have a functional reason to call by reference, you should stick to passing parameters regularly, because PHP does a great job of this.

(which, as others have pointed out, your sample code doesn't quite do what you think anyway;))

+1
source share
  • In the recursiveReference () function, you call the recursiveCopy () function. Is that what you really intended to do?
  • You are not doing anything with the variable $ foo - perhaps it should have been used in a later method call?
  • Passing a variable by reference usually should keep a memory stack when passing large objects.
0
source share

recursiveReference calls recursiveCopy. Not that this is necessarily harmful to performance, but it is probably not what you are trying to do.

Not sure why performance is slower, but it does not reflect the measurement you are trying to make.

0
source share

All Articles