I want to ask about a quirk that I happened upon. In truth, I expected my
code to fail with a fatal error, but it turns out that while using array
destructuring in the head of a foreach() loop it is permitted to declare
new elements if the value is a reference.
Is this a bug or an intended feature?
If not a bug should a note/section clarify this behavior?
https://www.php.net/manual/en/language.types.array.php
My demonstration can be found at this evidently unhelpful question:
https://stackoverflow.com/q/77741716/2943403
I don't know if this was designed this way purposefully, but it makes
sense to me. I see nothing out of the ordinary here. It makes for some
really nasty code, but that can probably be said about all code that
uses references.
If we try to simplify your example, we can see more clearly what's
happening. First, let's take the loop out of the equation.
$arr = [];
['foo' => &$v] = $arr;
$v = 1;
var_dump($arr);
This creates an array with one element whose value is 1 and key is
foo. That array restructuring is pretty much just a syntactic sugar
for an assignment operation. So we can simplify this example further
by replacing the array destructuring with this:
$v = & $arr['foo'];
Now, this looks like an average assignment of reference in PHP. The
rules of assignment-by-ref state:
If you assign, pass, or return an undefined variable by reference, it will get created.
https://www.php.net/manual/en/language.references.whatdo.php#language.references.whatdo.assign
Since array elements have similar logic to plain variables, this
applies to undefined keys, too. The foo key in the example above is
created initially with a NULL
value. Using the variable alias we
created, we can assign a different value to it.
Coming back to your example from SO, the array destructuring in
foreach is just a convoluted way of assignment-by-ref. After
simplifying it, it becomes:
foreach ($array as $key => $row) {
$x = & $array[$key]['new'];
$x = $row['bar'];
}
Which looks pretty normal to me. I would say it's definitely not a
bug. It's just a mix of two PHP features that together make up for
some confusing-looking code.