PHP references
Consider the following PHP code:
foreach ($things as $key => &$thing) { sort($thing); } # ... foreach ($things as $thing) { var_dump($thing); }
Two loops over the same array, separated by some amount of other code. The first loop uses an “&
” to indicate that $thing
should be referenced rather than copy-on-write.
This code will result in incorrect behavior because of PHP’s relaxed notion of scopes. The final iteration of the first loop will leave a reference to the last value in $things
stored in the variable $thing
. When the second loop runs, $thing
is still in scope and still a reference. The behavior in this case is to continually overwrite the referenced value with the value at each position in $things
. The end result is a corrupted $things
array in which the last two keys contain the same value and the original value at the last key has been lost. An example:
<?php $things = array( array("a" => "aa", "b" => "bb"), array("d" => "dd", "c" => "cc"), array("e" => "ee", "f" => "ff"), ); foreach ($things as $key => &$thing) { sort($thing); } # ... foreach ($things as $thing) { var_dump($thing); }
Running this code produces:
array(2) { [0]=> string(2) "aa" [1]=> string(2) "bb" } array(2) { [0]=> string(2) "cc" [1]=> string(2) "dd" } array(2) { [0]=> string(2) "cc" [1]=> string(2) "dd" }
The solution is simply to unset($thing)
after the first loop so the reference doesn’t linger:
foreach ($things as $key => &$thing) { sort($thing); } unset($thing) # ... foreach ($things as $thing) { var_dump($thing); }
I’ve been bitten twice by this problem. Both times Jesse has pointed it out and both times we discussed not using PHP as a preferable solution.