WARNING: Looping through "values by reference" for "extra performance" is an old myth. It's actually WORSE!
<?php
function one($arr) {
foreach($arr as $val) { echo $val;
}
}
function two($arr) {
foreach($arr as &$val) { echo $val;
}
}
$a = array( 'a', 'b', 'c' );
one($a);
two($a);
?>
Which do you think is faster?
Lots of people think the answer is two() because it uses "reference to value, which it doesn't have to copy each value when it loops".
Well, that's totally wrong!
Here's what actually happens:
* one():
- This function takes an array as argument ($arr).
- The array function argument itself isn't passed by reference, so the function knows it isn't allowed to modify the original at all.
- Then the foreach loop happens. The array itself wasn't passed by reference to the function, so PHP knows that it isn't allowed to modify the outside array, so it therefore makes a copy of the array's internal iteration offset state (that's just a simple number which says which item you are currently at during things like foreach()), which costs almost no performance or memory at all since it's just a small number.
- Next, it uses that copied iteration offset to loop through all key/value pairs of the array (ie 0th key, 1st key, 2nd key, etc...). And the value at the current offset (a PHP "zval") is assigned to a variable called $val.
- Does $val make a COPY of the value? That's what MANY people think. But the answer is NO. It DOESN'T. It re-uses the existing value in memory. With zero performance cost. It's called "copy-on-write" and means that PHP doesn't make any copies unless you try to MODIFY the value.
- If you try to MODIFY $val, THEN it will allocate a NEW zval in memory and store $val there instead (but it still won't modify the original array, so you can rest assured).
Alright, so what's the second version doing? The beloved "iterate values by reference"?
* two():
- This function takes an array as argument ($arr).
- The array function argument itself isn't passed by reference, so the function knows it isn't allowed to modify the original at all.
- Then the foreach loop happens. The array itself wasn't passed by reference to the function, so PHP knows that it isn't allowed to modify the outside array.
- But it also sees that you want to look at all VALUES by reference (&$val), so PHP says "Uh oh, this is dangerous. If we just give them references to the original array's values, and they assign some new value to their reference, they would destroy the original array which they aren't allowed to touch!".
- So PHP makes a FULL COPY of the ENTIRE array and ALL VALUES before it starts iterating. YIKES!
Therefore: STOP using the old, mythological "&$val" iteration method! It's almost always BAD! With worse performance, and risks of bugs and quirks as is demonstrated in the manual.
You can always manually write array assignments explicitly, without references, like this:
<?php
$a = array(1, 2, 3);
foreach($a as $key => $val) {
$a[$key] = $val * 10;
}
?>
The main lesson is this: DON'T blindly iterate through values by reference! Telling PHP that you want direct references will force PHP to need to copy the WHOLE array to protect its original values! So instead, just loop normally and trust the fact that PHP *is* actually smart enough to never copy your original array's values! PHP uses "copy-on-write", which means that attempting to assign something new to $val is the ONLY thing that causes a copying, and only of that SINGLE element! :-) But you never do that anyway, when iterating without reference. If you ever want to modify something, you use the "$a[$key] = 123;" method of updating the value.
Enjoy and good luck with your code! :-)