Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

foreach loop and reference of &$value

Why is an empty foreach loop can change the result.

I have the following code:

$variable = [1,2,3,4]; foreach ($variable  as $key => &$value)    $value ++;  var_dump($variable); 

The result I get is:

array (size=4)   0 => int 2   1 => int 3   2 => int 4   3 => &int 5 

Now, when I add an empty foreach loop like this:

$variable  = [1,2,3,4]; foreach ($variable  as $key => &$value)    $value ++;  foreach ($variable  as $key => $value);  var_dump($variable); 

I get this :

array (size=4)   0 => int 2   1 => int 3   2 => int 4   3 => &int 4 

can someone explain me why the last element doesn't change when I add the second empty loop, and why there is a & infront of the last element?

like image 724
Khalid Avatar asked Jul 23 '14 05:07

Khalid


People also ask

What is foreach loop with example?

In this program, foreach loop is used to traverse through a collection. Traversing a collection is similar to traversing through an array. The first element of collection is selected on the first iteration, second element on second iteration and so on till the last element.

Is C# foreach by reference?

Does a foreach loop iterate by reference? If you mean in the same sense as a C++ for loop by reference, then no. C# does not have local variable references in the same sense as C++ and hence doesn't support this type of iteration.

Is PHP foreach by reference?

This is an example why pass-by-reference in foreach loops is BAD. This is because when the second loop executes, $entry is still a reference. Thus, with each iteration the original reference is overwritten.

What is the function of foreach loop?

The foreach loop works only on arrays, and is used to loop through each key/value pair in an array.


1 Answers

At the end of the first loop, $value is pointing to the same place as $variable[3] (they are pointing to the same location in memory):

$variable  = [1,2,3,4]; foreach ($variable  as $key => &$value)      $value ++; 

Even as this loop is finished, $value is still a reference that's pointing to the same location in memory as $variable[3], so each time you store a value in $value, this also overwrites the value stored for $variable[3]:

foreach ($variable as $key => $value); var_dump($variable); 

With each evaluation of this foreach, both $value and $variable[3] are becoming equal to the value of the iterable item in $variable.

So in the 3rd iteration of the second loop, $value and $variable[3] become equal to 4 by reference, then during the 4th and final iteration of the second loop, nothing changes because you're passing the value of $variable[3] (which is still &$value) to $value (which is still &$value).

It's very confusing, but it's not even slightly idiosyncratic; it's the code executing exactly as it should.

More info here: PHP: Passing by Reference


To prevent this behavior it is sufficient to add an unset($value); statement after each loop where it is used. An alternative to the unset may be to enclose the foreach loop in a self calling closure, in order to force $value to be local, but the amount of additional characters needed to do that is bigger than just unsetting it:

(function($variable){    foreach ($variable  as $key => &$value) $value++; })($variable);  
like image 184
Adelmar Avatar answered Sep 27 '22 19:09

Adelmar