While destructuring array data in the head of a foreach() loop, can new elements be assigned to the original input array?

358 Views Asked by At

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

When using array destructuring within the head/signature of a foreach() loop, can new elements be declared instead of merely being accessed?

For example:

$array = [
    ['foo' => 'a', 'bar' => 1],
    ['foo' => 'b', 'bar' => 2],
];

Can I append a new element to each row of the original array with the key new?

2

There are 2 best solutions below

8
mickmackusa On BEST ANSWER

Yes, data can be appended to the rows of the original input array directly in the head of a foreach().

A general benefit of using array destructuring is the ability to specifically access/isolate data within a given array without loading unneeded data into a variable.

Details:

  • The new element must be declared by reference (the value must be a variable prepended with &) -- otherwise there is no indication to modify the original array.
  • If the reference variable is not later assigned a value, the default value will be null.

Code: (Demo)

$array = [
    ['foo' => 'a', 'bar' => 1],
    ['foo' => 'b', 'bar' => 2],
];

foreach ($array as ['new' => &$x, 'bar' => $x]);

var_export($array);

Output:

array (
  0 => 
  array (
    'foo' => 'a',
    'bar' => 1,
    'new' => 1,
  ),
  1 => 
  array (
    'foo' => 'b',
    'bar' => 2,
    'new' => 2,
  ),
)

Using the above sample input array, a body-less loop can be used to assign the first level keys as a new column in the array without declaring the full row as a reference. Code: (Demo)

foreach ($array as $x => ['new' => &$x]);

This approach requires one less globally-scoped variable to be declared versus:

foreach ($array as $x => &$row) {
    $row['new'] = $x;
}

and if not modifying by reference, the foreach() signature's required value variable isn't even used.

foreach ($array as $x => $row) {
    $array[$x]['new'] = $x;
}

Output (from all):

array (
  0 => 
  array (
    'foo' => 'a',
    'bar' => 1,
    'new' => 0,
  ),
  1 => 
  array (
    'foo' => 'b',
    'bar' => 2,
    'new' => 1,
  ),
)

Here is another answer that uses this technique and assigns values to the reference variables via another loop.


@Dharman mentioned in a PHP internals thread that array destructuring without a foreach() executes the same behavior. Demo

$arr = [];
['foo' => &$v] = $arr;
$v = 1;
var_export($arr);
// output: array('foo' => 1)

Although no longer supported, it was recommended that I clarify that for PHP7.1 through PHP7.2, this technique will cause a fatal error.

Fatal error: [] and list() assignments cannot be by reference

1
No Name On

In my opinion, it should be like this :

foreach ($bars as $trendy=>['new' => &$cocktail='Daiquiri', 'old'=>? $optional]);

  1. First quirk

foreach ($array as ['new' => &$x, 'bar' => $x])/*Where is 'new' ?*/;

I expected :

Fatal error: Redefinition of parameter $x

IMO it is better to write:

foreach ($array as &['new' => &$x, 'bar' => $y]) $y = $x;// affecting $array content;

almost like foreach($array as $key=>$row) $x = &$array[$key]['new']; $y=$array[$key]['bar']=$x;

or :

foreach ($array as ['new' => $x, 'bar' => &$y]) $y = $x;// affecting $array content almost like foreach($array as $key=>$row) $y = &$array[$key]['bar']; $y = $array[$key]['new'];

Ultimately, this has more consistency for me :

<?php
foreach ($array as ['new' => &$x, 'bar' => $y=$x]);
  1. Second quirk

foreach ($users as ['state' => $state, 'jobs' => &$ref[$state]]);

I expected :

Parse error: syntax error, unexpected token "[", expecting ")"

IMO it is better to write:

foreach ($users as ['state' => $state, 'jobs' => &$job]) $ref[$state]=$job;

or :

foreach ($users as &['state' => $state, 'jobs' => $jobs]) $ref[$state]=&$jobs;// Keept a reference of $users[0]['jobs']

  1. third quirk

foreach ($array as $x => ['new' => &$x])/* Where is my key $x ?*/;

I expected :

PHP Warning: Redefinition of parameter $x

  1. fourth quirk

The destructuring-rules of parser of PHP is similar to array construct. But on the one hand array() structures the data and constructs it at the same time.

In array('key'=>hydrate()) structur/construct you can call a fonction but in destructuring syntax I can't imagine it.

  1. fifth quirk

Why '&' create a new entry in the array ?

This is the behavior of PHP

function foo($new, int $old) {
    $ref = "Quirikou";
}
$trendly = ['old'=>0];
foo($trendly['new'], $trendly['old']);// Warning: Undefined array key "new" in
var_dump($trendly);

function baz(&$new, int $old) {
    $ref = "Quirikou";
}
$trendly = ['old'=>0];
baz($trendly['new'], $trendly['old']);


var_dump($trendly);