NuSphere Forums Forum Index
NuSphere Forums
Reply to topic
Debugging a foreach loop


Joined: 29 Sep 2004
Posts: 62
Location: �' AND sleep(21); /*
Reply with quote
Debugging the following foreach loop shows unexpected results:

$array = array(4, 7, 1, 5, 0, 12, 9);
// make sure each value is greater than or equal to the preceding value
foreach ($array as $index=>$value) {
if ( ($index+1) == count($array) )
break;
if ($array[$index] > $array[$index+1]) {
$array[$index+1] = $array[$index];
}
}

If you watch the $array and the $value they don't match.
For example, when $index is 2, $array[2] is 7 as expected, but $value is 1 (it should be 7).
The end result is correct once you finish the loop, but the value is wrong while you're in the foreach loop.
It seems the debugger works on an internal temp array and produces the $value from that array rather than from the actual $array.
Is this expected behavior? It drove me nuts until I figured what was actually happening.
View user's profileFind all posts by pointySend private messageVisit poster's websiteAIM AddressYahoo MessengerMSN Messenger
Site Admin

Joined: 13 Jul 2003
Posts: 8344
Reply with quote
Everything is okay with debugger
and $array[2] is 1, not 7 -- the beginning.
I'd recommend to check your code Smile one more time.
As soon as $index gets 1, your code copies value at the 1st index to the 2nd (and so forth).
Probably it's what you didn't take into account.

_________________
The PHP IDE team
View user's profileFind all posts by dmitriSend private messageVisit poster's website


Joined: 15 Sep 2007
Posts: 6
Reply with quote
Definitely nothing wrong with the debugger. I think the confusion is why $value is not the same as $array[$index] when the array value was changed during the previous iteration - the reason is that foreach is working on a copy of the array, not the actual array itself. So if you change the contents of the array while looping through it, it won't affect the copy of the array that your looping through. So, for example, during the iteration with an $index of 1, when $array[2] ($array[$index+1]) is changed from 1 to 7, when the foreach loops gets to the next iteration ($index of 2), $value will still be 1 (instead of the new value of 7). To make $value and $array[$index] the same, you would have to assign $value by reference, and then both $value and $array[$index] would always be the same.

Example with $value as reference:

$array = array(4, 7, 1, 5, 0, 12, 9);
// make sure each value is greater than or equal to the preceding value
// This example assigns $value by reference - $array[$index] and $value will be identical
foreach ($array as $index=>&$value) {
if ( ($index+1) == count($array) )
break;
if ($array[$index] > $array[$index+1]) {
$array[$index+1] = $array[$index];
}
}
View user's profileFind all posts by ldemonSend private message


Joined: 29 Sep 2004
Posts: 62
Location: �' AND sleep(21); /*
Reply with quote
Thanks ldemon, that answers my question. And I can see it's not a debugger issue but rather a php issue. However I made a change to the example and I'm still rather baffled.

I originally used a bad example because it always worked after leaving the foreach loop, though my actual code was quite different.
I think this example is a better illustration of the problem:

$array = array(0, 1, 2, 3, 4, 5, 6);
foreach ($array as $index=>$value) {
if ( ($index+1) < count($array) ) {
$array[$index+1] += $value;
}
echo $value." ";
}
echo "<br />";
foreach ($array as $index=>$value) {
echo $value." ";
}

You'd expect the output to be:
0 1 3 6 10 15 21
0 1 3 6 10 15 21

But it's actually:
0 1 2 3 4 5 6
0 1 3 5 7 9 11

Now if I change the code to assign the $value by reference as you rightly suggested:

$array = array(0, 1, 2, 3, 4, 5, 6);
foreach ($array as $index=>&$value) {
if ( ($index+1) < count($array) ) {
$array[$index+1] += $value;
}
echo $value." ";
}
echo "<br />";
foreach ($array as $index=>$value) {
$dummy = 1; // added for the debugger
echo $value." ";
}

it still does not produce the correct result:
0 1 3 6 10 15 21
0 1 3 6 10 15 15

If I watch the $array I see odd behavior for the last element $array[6] when stepping through the second foreach loop.
Just before entering the second loop $array[6] == 21 which is correct.
When I press F8 to get to the next line $array[6] == 0 !!
As I step through the loop $array[6] keeps on changing for each iteration, with the following values:
0, 1, 3, 6, 10, 15, 15
And once I've left the second loop $array[6] is permanently changed from 21 to 15, even though there is no code in the second loop to change $array[6].
So what is going on here?

BTW I agree this is not a debugger issue because if I change the code to:

$array = array(0, 1, 2, 3, 4, 5, 6);
foreach ($array as $index=>&$value) {
if ( ($index+1) < count($array) ) {
$array[$index+1] += $value;
}
echo $value." ";
}
echo "<br />";
foreach ($array as $index=>$value) {
$dummy = 1; // added for the debugger
echo $array[6]." ";
}
echo "<br />";
echo $array[6];

the result is:
0 1 3 6 10 15 21
0 1 3 6 10 15 15
15

And if I change the code to:

$array = array(0, 1, 2, 3, 4, 5, 6);
foreach ($array as $index=>&$value) {
if ( ($index+1) < count($array) ) {
$array[$index+1] += $value;
}
echo $value." ";
}
echo "<br />";
foreach ($array as $index=>&$value) {
$dummy = 1; // added for the debugger
echo $array[6]." ";
}
echo "<br />";
echo $array[6];

I finally get the correct result:
0 1 3 6 10 15 21
21 21 21 21 21 21 21
21

Have I really been using the foreach loop incorrectly for all these years? I always seemed to get the expected result up till now.

The following snippet is copied directly from the php manual:
foreach ($arr as $key => $value) {
echo "Key: $key; Value: $value<br />\n";
}

But the above example seems to indicate this isn't correct.
Still confused.
View user's profileFind all posts by pointySend private messageVisit poster's websiteAIM AddressYahoo MessengerMSN Messenger
Site Admin

Joined: 13 Jul 2003
Posts: 8344
Reply with quote
Look, it's very good that you're learning php here (I'm serious because I know that php can bring surprises time after time)
But I'm sorry to say that it's a bit out of scope of this forum. Most likely you want to ask your questions at php.general and php.internals newsgroup http://www.php.net/mailing-lists.php
btw, unexpected behaviour of foreach was discussed there multiple times.

As of debugger or phped, your questions are welcome if you think that debugger works wrong or unclear. In this case, you have to provide some info on what works differently with debugger than without it.

_________________
The PHP IDE team
View user's profileFind all posts by dmitriSend private messageVisit poster's website


Joined: 29 Sep 2004
Posts: 62
Location: �' AND sleep(21); /*
Reply with quote
Hi Dmitri, I originally thought it was a debugger problem, but as I clearly stated I realised it's not a debugger problem. I was merely (in a very long way) elaborating on the original problem that made me think it was a debugger problem, and was hoping some gurus here could shed some light on the issue. I have taken it up on the php forum. Didn't know the foreach problem had been discussed multiple times, though I've been on the php mailing list for many years.
View user's profileFind all posts by pointySend private messageVisit poster's websiteAIM AddressYahoo MessengerMSN Messenger
Site Admin

Joined: 13 Jul 2003
Posts: 8344
Reply with quote
for example, try to find "bug when using foreach with references?" subject in php.internals newsgroup. There are also some other discussions about foreach happened during all the years since the server started. Also I remember it was reported as error multiple times at bugs.php.net...
Regarding debugger - if you and anybody else believe they found an error, it's very simple to check - just comment off debugger and try the same code without it. If it works differently, you may want to contact our support and ask for help.

BTW, according to our history -- in most cases, it's Watch window with some forgotten function/method calls. You know you can call functions and methods here and they will certainly be called multiple times during debugging process. This may change the way your application works. Last time just 3 weeks ago one customer submitted report explaining that debugger would output "1" upon each stop in the debugger Smile... Guess what it was.

_________________
The PHP IDE team
View user's profileFind all posts by dmitriSend private messageVisit poster's website
Debugging a foreach loop
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
All times are GMT - 5 Hours  
Page 1 of 1  

  
  
 Reply to topic