Even by the usual PHP reference problems, this one is funky!
The real lesson here is that whenever you use a reference with foreach, always unset the reference variable afterwards, there’s too much potential pain otherwise 😛
Like so
Make sure your reference variables have unique names, kids!
I just unset and forget after the reference loop. Safer than checking for uniqueness
I don’t understand why it did that
The $array
variable continues to exist after the foreach
loop and continues to point to the last item seen in the loop (normally the last item in the array, unless break
was used).
We might think it contains the array item, normally, but in this case it contains a pointer/reference. References are meta-values that alter how variables are accessed.
When the new loop begins it tries to put the value into a variable, and sees that the variable is a reference and so puts it into the referenced location instead of the variable location.
after foreach loop $array is still a reference, there is no unset($array)
https://3v4l.org/B7qAe
It’s the same as if you replaced these two loops with this one:
It puts current element into third element.
I feel like implicitly redeclaring a variable that was already declared as a reference should probably throw some kind of warning.
Can you think of a legitimate use case for this behavior?
It’s not a declaration though. It’s just an assignment, and PHP allows you to reassign variables at will. In fact, assigning to references is 100% a feature, not a bug.
I mean, I agree it’s a sharp corner covering a live mine and it catches people unawares all the time, but it’s technically correct. The best kind of correct.
Ughghgh.
Neither Psalm, nor PHPStan are detecting this as an issue. 🙁
Which suggest that both are suckered into believing that second foreach is totally independent declaration that will overshadow previous one.
Good catch!
Neither Psalm, nor PHPStan are detecting this as an issue. 🙁 Which suggest that both are suckered into believing that second foreach is totally independent declaration that will overshadow previous one.
Tagging /u/muglug
Anytime you use a value by ref in a loop, you have to unset it after it is used. This is in the PHP foreach documentation: Reference of a $value and the last array element remain even after the foreach loop. It is recommended to destroy it by unset().