1

I ran into a weird issue and could reproduce it with this snippet:

<?php

$arr = [];

for($i = 0; $i <= 3; $i++) {
    $arr[] = [
        $i
    ];
}

foreach ($arr as &$item) {
    $item[] = $item[0];
}

foreach ($arr as $item) {
    print_r($item);
}

It is outputting (notice the last element had been replaced with a copy of its previous one):

Array
(
    [0] => 0
    [1] => 0
)
Array
(
    [0] => 1
    [1] => 1
)
Array
(
    [0] => 2
    [1] => 2
)
Array
(
    [0] => 2
    [1] => 2
)

However, here's the expected result:

Array
(
    [0] => 0
    [1] => 0
)
Array
(
    [0] => 1
    [1] => 1
)
Array
(
    [0] => 2
    [1] => 2
)
Array
(
    [0] => 3
    [1] => 3
)

If I use array_map instead of the first foreach, it works:

<?php

$arr = [];

for($i = 0; $i <= 3; $i++) {
    $arr[] = [
        $i
    ];
}

$arr = array_map(function ($item) {
    $item[] = $item[0];
    return $item;
}, $arr);

foreach ($arr as $item) {
    print_r($item);
}

Tested under PHP 8.0.0.

What could be causing this difference? Is there something about array pointers I'm missing?

2 Answers2

0
$arr = [];

for($i = 0; $i <= 3; $i++) {
    $arr[] = [
        $i
    ];
} 
/** Output 
* $arr = [[0],[1],[2],[3]]
*/

In this foreach loop you are just selecting the existing value of item and setting it into a new index of referenced item

foreach ($arr as &$item) {
    $item[] = $item[0];
}

Type of $item is array, $item[0] is referred to its 0 index $item[] means a new array index inside item that is currently referenced to.

Mohsen Amani
  • 82
  • 1
  • 8
0

In your first example, the $item variable still holds a reference to the last value of the $arr when the loop is done.

foreach ($arr as &$item) {
    $item[] = $item[0];
}

If you use print_r(get_defined_vars()); you can see that there is a key in the array with name item

The behaviour of the double value at the end of the foreach is described here and It is recommended to destroy the specified variables using unset($item)

You can also use a different variable name.


Using array_map, the callback gets a function argument passed by name, which is bound to the function scope.

If you run print_r(get_defined_vars()); after using array_map you can see that there is no key named item

The fourth bird
  • 154,723
  • 16
  • 55
  • 70
  • Interesting... indeed using a different variable name other than `$item` at the second foreach removes the ending dupe... The first foreach's final iteration marks `$item` as a reference to the array's last item, and the second foreach statement reassigns it over and over (since it is a reference, reassigns the referenced value), causing the last item to be lost... did I understand correctly? – Jefrey Sobreira Santos Jan 13 '22 at 13:55
  • 1
    Nvm... there's indeed a huge red box warning about exactly the behavior I faced on the linked docs. Coding while affected by covid has its drawbacks... Thank you for all responses! – Jefrey Sobreira Santos Jan 13 '22 at 13:57