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.