I am trying to iterate an associative array with a foreach loop using :
i) key value pair line 4-7
ii) only the value line 11-16
The Code, Output and Problem is as follows:
*Code
=====
PHP Code:
$testArray = array("first"=>"Mon","second"=>"Tuesday","third"=>"Wednesday","fourth"=>"Thrusday"); print_r($testArray); echo "<p><strong>Iterating with key,value </strong></p>"; foreach($testArray as $key=>$value) { echo "<p>Key: ", $key, " is $value </p>"; } //$NotUsed = $testArray; //reset($testArray); echo "<p><strong>Iterating with value </strong></p>"; foreach($testArray as $test) { echo "<p>Key: ", key($testArray)," Current value: ",current($testArray),"</p>"; echo "<p>Value: $test</p>"; next($testArray); }
I am not able to iterate the keys of the associative array correctly in the second foreach loop.
The code somehow works if I enable the assignment at line 8. $NotUsed = $testArray;
Whilst i dont understand why it is that you are getting this strange output, i cant help but wonder why it is that you cant use the foreach($data as $key=>$value) system. as you have shown in the example, that works. why would you need to use that system?
key, current and next functions are inbuilt PHP functions for iterating an array
key(array) - Returns key of the current array element
current(array) - Returns the current array element
next(array)- Moves the internal array pointer to the next element
Yes the first foreach loop is the traditional way to iterate through the array.
I just happened to use the second foreach loop and was trying to access the corresponding keys in the loop and got this weird output. So I am wondering if it some internal bug?
The reason that the key(), current(), and next() inside the foreach() loop are not operating as expected is because the foreach() loop is operating on a copy of the array and the key(), current(), and next() are operating on the actual array. If you comment out the next(), you will see that the key() and current() don't advance.
The real problem appears to be that the reset() statement does not seam to be resetting the actual array pointer (and the previous foreach() loop did not leave the pointer after the last element as it is supposed to), but referencing the array in an assignment statement did reset it.
Short answer - key(), current(), and next() reference the actual array while a foreach() loop uses a copy of the array, don't use key(), current(), and next() inside of a foreach() loop, there is no need (and I will bet the code takes twice as long to execute because you are duplicating what the foreach() is doing inside of the foreach() loop.)
BTW: The , will only work in an echo statement, as it accepts a coma separated list of parameters -
Quote:
void echo ( string $arg1 [, string $...] )
This is not actually concatenating a string using the .
__________________
Error checking, error reporting, and error recovery. If your code does not have these to get it to tell you why it is not working, what makes you think someone in a programming forum will be able to tell you why it is not working???
Last edited by mab; 11-09-07 at 11:47 AM.
Reason: add , info
I played with the code a bit and the reset() statement does in fact reset the actual array pointer (echo something with key() and current() in it immediately after the reset()) and the previous foreach() loop is leaving the array pointer after the last element as it should.
What I suspect is happening is some short-circuit optimization. When the second (any) foreach() loop sees that the array has not been directly referenced, it is apparently not bothering with the actual array pointer until after the loop finishes (it does appear to be resetting it and incrementing it once, leaving it pointing to the second element for the duration of the loop.)
I tested some more and when the array has been referenced at all (put the $NotUsed = $testArray; after the array() statement and before the first foreach() loop and comment out the one before the second foreach() loop) the foreach() is resetting the actual array pointer but is leaving it pointing to the first element for the duration of the loop.
So, somehow the foreach loop is detecting a "no-reference" state of the array and is either leaving the actual array pointer pointing to the first element or to the second element for the duration of the loop, depending on if the array has been previously referenced or not.
Short answer - use a foreach() loop the way it was meant to be, and don't directly access the array elements using key(), current(), and next() inside of a foreach() loop.
__________________
Error checking, error reporting, and error recovery. If your code does not have these to get it to tell you why it is not working, what makes you think someone in a programming forum will be able to tell you why it is not working???
Thanks for extended testing with this piece of code.
The foreach does operates on the copy of the array. The key(),next() and current() are normally not meant to be used outside the foreach, but could be used for some processing reasons.
But this is clear that the foreach does alter the original internal pointer of the associative array to the second element which should have been the first element.
And somehow it does not alter the original internal pointer if the array is part of the assignment statement just before the foreach loop.
Is this a bug?
Thanks,
Divya
Quote:
Originally Posted by mab
I played with the code a bit and the reset() statement does in fact reset the actual array pointer (echo something with key() and current() in it immediately after the reset()) and the previous foreach() loop is leaving the array pointer after the last element as it should.
What I suspect is happening is some short-circuit optimization. When the second (any) foreach() loop sees that the array has not been directly referenced, it is apparently not bothering with the actual array pointer until after the loop finishes (it does appear to be resetting it and incrementing it once, leaving it pointing to the second element for the duration of the loop.)
I tested some more and when the array has been referenced at all (put the $NotUsed = $testArray; after the array() statement and before the first foreach() loop and comment out the one before the second foreach() loop) the foreach() is resetting the actual array pointer but is leaving it pointing to the first element for the duration of the loop.
So, somehow the foreach loop is detecting a "no-reference" state of the array and is either leaving the actual array pointer pointing to the first element or to the second element for the duration of the loop, depending on if the array has been previously referenced or not.
Short answer - use a foreach() loop the way it was meant to be, and don't directly access the array elements using key(), current(), and next() inside of a foreach() loop.
In your original code you commented out the reset function.
And that is what you need to get your code to work.
The foreach statement moves the array pointer the first time
it executes, before it makes a copy. So you must reset the pointer once.
Like this:
PHP Code:
<?php $testArray = array("first"=>"Mon","second"=>"Tuesday","third"=>"Wednesday","fourth"=>"Thrusday"); print_r($testArray); echo "<p><strong>Iterating with key,value </strong></p>"; foreach($testArray as $key=>$value) { echo "<p>Key: ", $key, " is $value </p>"; } echo "<p><strong>Iterating with value </strong></p>"; foreach($testArray as $test) { if(!isset($sw)){reset($testArray);$sw = 1;} echo "<p>Key: ", key($testArray)," Current value: ",current($testArray),"</p>"; echo "<p>Value: $test</p>"; next($testArray); } ?>
In the testing I did, I included the line with the reset() and it does reset the pointer (I echoed a line using key() and current() immediately after it.)
The issue is a foreach() loop does not maintain the actual array pointer inside of the loop, it maintains its own copy of the array pointer, then sets the actual array pointer to be after the last element in the array after the end of the loop.
The foreach() loop provides access to a value or key/value directly through the foreach() language construct. Using key()/current() to access the same things is simply ignoring the definition of the foreach() language construct.
By using key/current/next inside of a foreach() loop, you are executing twice the amount of code, taking twice the amount of processing time, to do something that the foreach() loop was designed to do by itself. There is no common sense reason to be doing this.
__________________
Error checking, error reporting, and error recovery. If your code does not have these to get it to tell you why it is not working, what makes you think someone in a programming forum will be able to tell you why it is not working???