2

I am new to PHP and I am experimenting
right now with some foreach loops in PHP.

I know that it is recommended to unset
the foreach loop variables after the loop.

I noticed that if I include the lines // 1 // and
// 2 //, this script prints the right thing.

... 
Name: Rachel, Age: 56
Name: Grace, Age: 44

( It also prints the right thing if in the last loop, I use other
variable names like $n and $a instead of $name and $age.)

But if I comment lines // 1 // and // 2 // out, it prints:

Name: Lisa, Age: 28
Name: Jack, Age: 16
Name: Ryan, Age: 35
Name: Rachel, Age: 46
Name: Grace, Age: 34

Name: Lisa, Age: 38
Name: Jack, Age: 26
Name: Ryan, Age: 45
Name: Rachel, Age: 56
Name: Grace, Age: 56

Notice that 56 is printed two times.
Why does it behave that way?
I mean: what happens under the hood?

<?php

$employee_age = array();
$employee_age["Lisa"] = "28";
$employee_age["Jack"] = "16";
$employee_age["Ryan"] = "35";
$employee_age["Rachel"] = "46";
$employee_age["Grace"] = "34";

foreach( $employee_age as $name => $age){
    echo "Name: $name, Age: $age <br />";
}

echo "<br>";
unset($age);
unset($name);

foreach( $employee_age as $name => &$age){
    $age += 10;
}

// echo "<br>";
// unset($age); // 1 //
// unset($name); // 2 //

foreach( $employee_age as $name => $age){
    echo "Name: $name, Age: $age <br />";
}

echo "<br>";
unset($age);
unset($name);

?>
Roman C
  • 49,761
  • 33
  • 66
  • 176
peter.petrov
  • 38,363
  • 16
  • 94
  • 159

4 Answers4

2

If you var_dump($employee_age) before the second loop you'll notice that the last entry say &int instead of int. It is still a reference. It points to the last element (ignoring itself). And that is Rachel with 56.

Look into the manual's warning: http://pl.php.net/manual/en/control-structures.foreach.php

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

Sbls
  • 495
  • 1
  • 4
  • 10
  • Well, OK, I know they remain there but then wouldn't the last loop overwrite them anyway? And why is the mistake happening on the last iteration of the last loop and not on the first iteration?! – peter.petrov Dec 28 '13 at 16:18
  • 2
    @peter.petrov I think what you're looking for is [here](http://stackoverflow.com/a/8220457/1031955) – Thanakron Tandavas Dec 28 '13 at 16:23
  • @ThanakronTandavas Why did you remove your answer? It was closest to my problem I think. Thanks. I will read the page you provided. – peter.petrov Dec 28 '13 at 16:24
  • To be short: $employee_age['Grace'] points to $age. So everytime you use $age it gets overwritten. You can visualize that if you `var_dump($employee_age)` inside the last foreach loop. – Sbls Dec 28 '13 at 16:26
  • @peter.petrov I thought Sbls already answered what you are looking for. – Thanakron Tandavas Dec 28 '13 at 16:26
1

It's PHP's behavior of a referenced item.

Reason : I think this guy can explain better than me.

Just a little memo.

Alternatively, to fix this, you can add & to $age at your third foreach:

foreach( $employee_age as $name => &$age){
    echo "Name: $name, Age: $age <br />";
}
Community
  • 1
  • 1
Thanakron Tandavas
  • 5,615
  • 5
  • 28
  • 41
  • 1
    OK, this is a pretty weird behavior, I guess anyone coming to PHP would agree, but the link you provided gives a very good explanation why it behaves that way :) So thanks again. – peter.petrov Dec 28 '13 at 16:41
  • No problem. Agree, animuson♦ explained this behavior very well. – Thanakron Tandavas Dec 28 '13 at 16:43
  • I disagree with fix part here. If you wish to destroy reference, use `unset($age);` after foreach where you have used it. – Glavić Dec 28 '13 at 17:45
  • @Glavić True. Since the guy already used `unset($age);` in his code, I forgot to mention that this is an alternative. Nice catch. – Thanakron Tandavas Dec 28 '13 at 17:47
0

Hm.. not sure why you unset,

simpler:

    $employee_age = array(
    "Lisa"   => 28,
    "Jack"   => 16,
    "Ryan"   => 35,
    "Rachel" => 46,
    "Grace"  => 34);

    foreach( $employee_age as $name => $age){
        echo "Name: $name, Age: $age <br />";
    }

    echo "<br>";

    foreach( $employee_age as $name => $age){
        $age2 = $age + 10; // (Don't think this is required)
        echo "Name: $name, Age: $age2 <br />"; // Try with just $age+10
    }

?>
Jelle Ferwerda
  • 1,254
  • 1
  • 7
  • 13
  • 1
    Why use the `&` then in the second loop? – Bart Friederichs Dec 28 '13 at 16:11
  • 1
    Jelle, which part of my question does that answer? – peter.petrov Dec 28 '13 at 16:12
  • Peter, I reworked your code so it should not give you that problem. Personally, I prefer to not work with variables by reference. If you need to keep the modified ages, I would work in the array, to keep it clear what you are changing when. – Jelle Ferwerda Dec 28 '13 at 16:15
  • OK, I get your answer: it says basically "avoid doing this". Thanks. But as I said I am just learning the foreach loop, and found this weird behavior. So OK, I know how to get it working OK, NP. I just don't know why it prints two times the 56. – peter.petrov Dec 28 '13 at 16:17
0

Grace = 56 because your code is;

foreach( $employee_age as $name => &$age){
    $age += 10;
}

Change it to

foreach( $employee_age as $name => $age){
    $age += 10;
}

And Grace will 34 again.