12

I have a doubt in php foreach iteration.

Please look my below code.

CODE :

   $arr=array(1,2,3);

    echo '$arr value : '. $arr;

    echo '<br>';

    foreach($arr as $arr){
        echo $arr.'<br>';
    }
    echo '$arr value : '. $arr;

OUTPUT :

$arr value : Array
1
2
3
$arr value : 3

While iterating array i used same array name to value key foreach($arr as $arr) but it works fine. How it is working?.

Why it doesn't override the array value while iterating?

I want to know how foreach iteration is working.

Please Help me!

Thanks in advance Logan

3
  • doesnt php somehow cache the content of the original $arr(the array), then while looping, it changes and shows the $arr (as 1, 2 and 3), then at the end the $arr is left as "3", as it just doesnt save the cached value, back into the original file, because php doesnt expect u to be overriding it .. Commented Sep 7, 2012 at 6:50
  • @PraveenKumar Please double check my question Commented Sep 7, 2012 at 6:51
  • @loganphp I saw it too. Well, er... :P I don't have an answer. It is something that deals with the internal working of PHP Interpreter itself. :) Commented Sep 7, 2012 at 7:24

8 Answers 8

14

Why it doesn't override the array value while iterating?

foreach will work on a copy of the original array so things you change in the foreach loop will not change the values you are looping over.

Sign up to request clarification or add additional context in comments.

Comments

3

PHP uses a copy on write or lazy copy mechanism with reference counting for memory handling.

In the first stage of foreach iteration, $arr is "soft copied" (no actual copy, but only the refcount of the zval of $array is increased). checkout variable container and label of PHP variables.

In our case,

  • it first keep a reference to actual $arr variable, and the first value of array is fetched from the reference point.
  • For later use first array element is assigned to second $arr foreach($arr as $arr)
  • In the next iteration, second array value is fetched from previously saved reference point, and that value is assigned to same $arr and continues.
  • As value of $arr is changed inside loop, you cannot print that array outside loop using $arr variable.

Hope you can understand...

For an in-depth study checkout http://www.php.net/manual/en/internals2.opcodes.fe-fetch.php and http://www.php.net/manual/en/internals2.opcodes.fe-reset.php

Interestingly you can play with this too...

current() inside a foreach loop will always returns the same element!!!

Code

$source = array(10, 20, 30);
foreach ($source as $value) {
    echo 'Value is ', $value, ', and current() is ', current($source), '<br>';
}

Output

Value is 10, and current() is 20
Value is 20, and current() is 20
Value is 30, and current() is 20

Comments

1
foreach ($arr as $arr) {
    // code
}

This may be confusing to you because your mental model of how this works is:

  1. PHP takes the current element out of $arr and advances the array pointer
  2. it assigns the value to $arr
  3. it executes // code
  4. it repeats from step one

What it actually does though is this (or at least an approximate simplification of it):

  1. PHP starts the foreach operation, taking the array value that is associated with $arr
  2. it puts this array somewhere internally, let's say a var iterator
  3. it takes the current element from var iterator and advances the iterator
  4. it assigns the value it took to $arr in your script
  5. it executes // code
  6. it repeats from step 3

In other words, it does not take the next value from $arr on every iteration, it only used this once to get the initial iterator. The actual thing that it iterates over is stored internally and is not associated with $arr anymore. That means $arr is free for other purposes in your script and PHP is happy to reuse it on each iteration. After the loop is done, the last element remains in $arr.

If you know anonymous functions, maybe this illustrates better why this works the way it works:

foreach($arr, function ($arr) {
    // code
});

The implementation of such a foreach function can be simply this:

function foreach(array $array, callable $code) {
    while (list(, $value) = each($array))  {
        $code($value);
    }
}

2 Comments

+1, except that your illustrative example at the end doesn't explain why $arr is changed after the loop :-)
Well yes, in the anonymous function the $arr doesn't leak into the surrounding scope. That's really is the least complicated thing I'd think though, because the "loop variable is still available after the loop and has the last value" thing works the same regardless of the variable name... :)
0

$arr and $arr are same in your code.Source array and reference variable are having same name.So foreach keeps the value that was last recieved it doesnt relinquishes the variable.

Comments

0

foreach use a copy of the original array, so you could think the code

foreach($arr as $arr){
    echo $arr.'<br>';
}

is just like below:

for ($i = 0, $arr_tmp = $arr, $len = count($arr_tmp); $i < $len; $i++) {
  $arr = $arr_tmp[$i];
  echo $arr.'<br>';
}

This explains why the $arr is 3 at last.

Comments

0

you are over writing the array when you fetch a record , you are asking the code to fetch a record from $arr and put it into the array named $arr so you are over writing the whole array with single parameter before $arr = {1,2,3}; after this line and first iteration foreach ($arr as $arr) now the the $arr is equal to 3 which the last element of the array , i hope you under stand the problem

Comments

-1

Hmm, after a bit of investigating I came up with this code:

<?php
$arr=array(1,2,3);

echo '$arr value : '. $arr;

echo '<br>';

foreach($arr as $arr){
    echo $arr.'<br>';
}

foreach($arr as $key) {
    echo $key.'<br>';
}
echo '$arr value : '. $arr;

Which had this output:

$arr value : Array
1
2
3
PHP Warning:  Invalid argument supplied for foreach() in ...file...

My read on this is that the second $arr is shadowing the first one while inside the foreach loop, but as soon as it exits the foreach loop it internally unsets the symbol ($arr)

2 Comments

It doesn't unsets it, it overrides it with the last value the foreach has in loop. So you second foreach is trying to loop over an single value, not an array
Didn't even think of that, that's even worse.
-2

foreach first evaluates the left side before iterating over its elements. Therefore, the reassignment to the name $arr does not modify $arr.

Furthermore, the loop variable leaks into the outer context, as documented:

Reference of a $value and the last array element remain even after the foreach loop. It is recommended to destroy it by unset().

Of course, to avoid the confusion, you should simply use a different name for the loop variable than for the array you're looping over:

$arr=array(1,2,3);
foreach($arr as $a) { // Note the "as $a", not "as $arr"
    echo $a.'<br>';
}
echo '$arr value : '. $arr;

2 Comments

I think that's the question - why does it work the way it does when the variables have the same name.
@MarekKarbarz Amended the answer with that.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.