passing a variable in foreach (bug og strange behaviour?)

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

Post Reply
alfmarius
Forum Newbie
Posts: 16
Joined: Thu Jul 10, 2008 5:14 am

passing a variable in foreach (bug og strange behaviour?)

Post by alfmarius »

Hello :)

I'm experiencing some strange behaviour in passing a variable in a foreach:

Code: Select all

$a = array("a" => 1, "b" => 0, "c" => 1);
foreach ($a as $key => &$value) {
  if ($value) {
    $value++;
  } else {
    unset($a[$key]);
  }//if-else
}//foreach
 
Outputs:
 
Array
(
    [a] => 2
    [c] => 1
)
 
My original array is much larger, but $a is enough to explain my point here.
I would expect $a[c] to be 2 also, but it isn't, and I have a very hard time
to try to explain to myself why it is like this..

Any ideas ?

:roll:
User avatar
jayshields
DevNet Resident
Posts: 1912
Joined: Mon Aug 22, 2005 12:11 pm
Location: Leeds/Manchester, England

Re: passing a variable in foreach (bug og strange behaviour?)

Post by jayshields »

Don't know about fixing what you already have, but try this:

Code: Select all

 
$a = array("a" => 1, "b" => 0, "c" => 1);
foreach ($a as $key => $value) {
  if ($value) {
    $a[$key]++;
  } else {
    unset($a[$key]);
  }//if-else
}//foreach
 
alfmarius
Forum Newbie
Posts: 16
Joined: Thu Jul 10, 2008 5:14 am

Re: passing a variable in foreach (bug og strange behaviour?)

Post by alfmarius »

Thanks. Yes I know this is also possible, in fact it is how I usually do things. Then I wanted to experiemnt with passing variables, because it looks and reads better. Thats when i stumbled uplon this strange behaviour. Could it be a bug?
User avatar
VladSun
DevNet Master
Posts: 4313
Joined: Wed Jun 27, 2007 9:44 am
Location: Sofia, Bulgaria

Re: passing a variable in foreach (bug og strange behaviour?)

Post by VladSun »

alfmarius wrote:Could it be a bug?
Sure :)
http://bugs.php.net/bug.php?id=29992
There are 10 types of people in this world, those who understand binary and those who don't
alfmarius
Forum Newbie
Posts: 16
Joined: Thu Jul 10, 2008 5:14 am

Re: passing a variable in foreach (bug og strange behaviour?)

Post by alfmarius »

VladSun wrote:
alfmarius wrote:Could it be a bug?
Sure :)
http://bugs.php.net/bug.php?id=29992
Thanks for the reply Vlad, but after reading that bug report link, the conclusion of it was that it really wasn't a bug, just strange behaviour. And the case was not exactly the same, in the example they used two foreach loops. Maby the point would be the same, I just couldn't wrap my head around it.

Anyway, I did some more testing:

Code: Select all

$array = array("a" => 1, "b" => 0, "c" => 1);
foreach ($array as $key => &$value) {
var_dump($value);print "<br>";
var_dump($array);print "<br>";
 if ($value) {
   $value = 5;
 } else {
   unset($array[$key]);
 }//if-else
}//foreach
print "<br>";
var_dump($array);
This will output:

Code: Select all

int(1)
array(3) { ["a"]=> ?(1) ["b"]=> int(0) ["c"]=> int(1) }
int(0)
array(3) { ["a"]=> ?(5) ["b"]=> ?(0) ["c"]=> int(1) }
int(1)
array(2) { ["a"]=> ?(5) ["c"]=> int(1) }
 
array(2) { ["a"]=> int(5) ["c"]=> int(1) }
There is a new character ? that I'm not familiar with.
Everything goes as expected untill we get to b which is 0, unsets it and goes on to c. What seems to be the bug/problem is when $value is 0 and we unset the array-element that $value points to. I would expect $value to just point to the next element when going to the top of the foreach, but this doesn't happen. I have a very hard time to find out what really happens, if it is logical (and very strange) or if it is a bug.

Any comments on this last "insight"?

..it's fun to dig deep isn't it? ;)
User avatar
VladSun
DevNet Master
Posts: 4313
Joined: Wed Jun 27, 2007 9:44 am
Location: Sofia, Bulgaria

Re: passing a variable in foreach (bug og strange behaviour?)

Post by VladSun »

PHP 5.2.5

Code: Select all

$array = array("a" => 1, "b" => 0, "c" => 1);
foreach ($array as $key => &$value) {
var_dump($value);print "<br>";
var_dump($array);print "<br>";
 if ($value) {
   $value = 5;
 } else {
   unset($array[$key]);
 }//if-else
}//foreach
print "<br>";
var_dump($array);
Output:

Code: Select all

int 1
 
array
  'a' => &int 1
  'b' => int 0
  'c' => int 2
 
int 0
 
array
  'a' => int 5
  'b' => &int 0
  'c' => int 2
 
int 2
 
array
  'a' => int 5
  'c' => &int 2
 
array
  'a' => int 5
  'c' => &int 5
Sorry, couldn't reproduce it.
And yes - I should have read the rest of the page I pointed to :)
There are 10 types of people in this world, those who understand binary and those who don't
User avatar
Benjamin
Site Administrator
Posts: 6935
Joined: Sun May 19, 2002 10:24 pm

Re: passing a variable in foreach (bug og strange behaviour?)

Post by Benjamin »

Note: Unless the array is referenced, foreach operates on a copy of the specified array and not the array itself. foreach has some side effects on the array pointer. Don't rely on the array pointer during or after the foreach without resetting it.
http://us3.php.net/manual/en/control-st ... oreach.php

$value is not referenced to $array[%n] and even if it was $array[%n] would be a copy of the original. Why would you expect that to work? Additionally, even if you were working with a referenced copy, the manual states that changing the content of an array while your iterating it with a foreach loop can lead to unpredictable results.
alfmarius
Forum Newbie
Posts: 16
Joined: Thu Jul 10, 2008 5:14 am

Re: passing a variable in foreach (bug og strange behaviour?)

Post by alfmarius »

Hi Astions, thank you for taking your time with this :)
astions wrote:
Note: Unless the array is referenced, foreach operates on a copy of the specified array and not the array itself. foreach has some side effects on the array pointer. Don't rely on the array pointer during or after the foreach without resetting it.
http://us3.php.net/manual/en/control-st ... oreach.php
"foreach has some side effects on the array pointer. Don't rely on the array pointer during or after the foreach without resetting it."
I find this piece of the sentence a little disturbing. And the whole sentence starts with "Unless the array is referenced..", so I'm not sure if they mean the internal pointer in an unreferenced or referenced foreach. It doesn't state what are the side effects, and to what degree we can actually trust a referenced foreach. But I clearly get the message that one might experience some smelly fish while doing unordinary things in a referenced foreach loop.
astions wrote: $value is not referenced to $array[%n] and even if it was $array[%n] would be a copy of the original. Why would you expect that to work? Additionally, even if you were working with a referenced copy, the manual states that changing the content of an array while your iterating it with a foreach loop can lead to unpredictable results.
Now I'm confused. $value is not a reference to an arrays values in a foreach loop?? I thought that was the point of &$value.. I couldn't find anywhere in the foreach manual that stated that changing the content of an array while foreach-ing it can lead to unpredictable results (maby you mean somewhere else, or in the comments? ..didn't read all of them)
VladSun wrote:Sorry, couldn't reproduce it.
And yes - I should have read the rest of the page I pointed to :)
That reply might be the one that cleared things up a little bit. It, and the fact that I am useing PHP 5.2.0-8+etch11 myself, got me into searching the changelog for more answers. I think I found something in this one:

Bug #35106: nested foreach fails when array variable has a reference
http://bugs.php.net/bug.php?id=35106

The scenario described is not exactly the same as mine, but it certainly resembles it. And considering that this bug was fixed between v5.2.0 and v5.2.1, it might be the fix that makes your (Vlads) results differ from mine. I suspect you have a typo with the c value being 2 and not 1 though? ;)

To conclude: It's seems the suspicious behavior I was experiencing in fact was a bug, that has now been fixed with PHP versions >= 5.2.1

:mrgreen:
User avatar
VladSun
DevNet Master
Posts: 4313
Joined: Wed Jun 27, 2007 9:44 am
Location: Sofia, Bulgaria

Re: passing a variable in foreach (bug og strange behaviour?)

Post by VladSun »

alfmarius wrote:I suspect you have a typo with the c value being 2 and not 1 though? ;)
Oh ...
My code was:

Code: Select all

$array = array("a" => 1, "b" => 0, "c" => 2);
So I was able to differ "a" and "c".
There are 10 types of people in this world, those who understand binary and those who don't
Post Reply