5

Since PHP7.1, a foreach() expression can implement array destructuring as a way of unpacking row values and make individualized variable assignments.

When using array destructuring within a foreach() loop, can a specific value be accessed by its associative key more than once?

For example:

$array = [
    ['group' => 'A', 'name' => 'Ann', 'age' => 19],
    ['group' => 'B', 'name' => 'Bea', 'age' => 26],
    ['group' => 'A', 'name' => 'Cam', 'age' => 32],
    ['group' => 'B', 'name' => 'Des', 'age' => 24]
];

I know I can use:

foreach ($array as ['group' => $group, 'name' => $name, 'age' => $age]) {
    // do stuff with $group, $name, and $age
}

But what if I want to access, say, $group a second time while destructuring? Is it possible?

mickmackusa
  • 43,625
  • 12
  • 83
  • 136

1 Answers1

6

It looks pretty unorthodox and there will be very few scenarios when it is useful, but yes it is possible/valid.

Just repeat the "key => value" syntax again and provide a different variable in the value position. In this context, the keys may be repeated.

Here is a demonstration of using array destructuring to "pivot" a result set with a body-less foreach loop.

Code: (Demo)

$array = [
    ['group' => 'A', 'name' => 'Ann', 'age' => 19],
    ['group' => 'B', 'name' => 'Bea', 'age' => 26],
    ['group' => 'A', 'name' => 'Cam', 'age' => 32],
    ['group' => 'B', 'name' => 'Des', 'age' => 24]
];

$result = [];
foreach ($array as ['group' => $group, 'group' => $result[$group]['group'], 'name' => $name, 'age' => $result[$group][$name]]);
# 1st assignment of group value^^^^^^
# 2nd assignment of group value-------------------^^^^^^^^^^^^^^^^^^^^^^^^

var_export($result);

Output:

array (
  'A' => 
  array (
    'group' => 'A',
    'Ann' => 19,
    'Cam' => 32,
  ),
  'B' => 
  array (
    'group' => 'B',
    'Bea' => 26,
    'Des' => 24,
  ),
)

Key access is not restricted to static values; array keys can be dynamically accessed: (Demo)

$array = [
    ['group' => 'A', 'A' => 1, 'B' => 2,],
    ['group' => 'B', 'A' => 3, 'B' => 4,],
    ['group' => 'A', 'A' => 5, 'B' => 6,],
    ['group' => 'B', 'A' => 7, 'B' => 8,]
];
$result = [];
foreach ($array as ['group' => $group, $group => $result[$group][]]);
var_export($result);

Output:

array (
  'A' => 
  array (
    0 => 1,
    1 => 5,
  ),
  'B' => 
  array (
    0 => 4,
    1 => 8,
  ),
)

The same technique works outside of the context of a foreach() loop as well. (Demo)

['one' => $result[], 'one' => $result[]] = ['one' => 1];
var_export($result);

Output:

array (
  0 => 1,
  1 => 1,
)
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
  • Interesting. Very useful for obfuscating code (especially the last one), but anywhere else? – Nick Apr 10 '22 at 07:27
  • This is a very, very fresh discovery for me. I haven't had much time to consider possible scenarios where this "feature" is noticeably beneficial. – mickmackusa Apr 10 '22 at 09:08
  • I'll be interested to hear if you come up with something... – Nick Apr 10 '22 at 09:08
  • (I guess this is where I ask you to "follow" this page.) The second snippet might be used like a `array_multi_push()` if you wanted to add an element to two different arrays at the same time. ...I guess. – mickmackusa Apr 10 '22 at 09:09
  • 1
    Well, I've followed. We'll see what comes up... – Nick Apr 10 '22 at 12:26
  • I'm hanging for PSR guidelines to tell me how to multi-line the destructured `foreach()`. It seems yet to be described. – mickmackusa Apr 10 '22 at 12:36