Here is a simple loop
$list = array("A", "B", "C","D"); foreach ($list as $var) { print(current($list)); }
Output (demo)
BBBB // Output for 5.2.4 - 5.5.0alpha4 BCD // Output for 4.4.1 AAAA // Output for 4.3.0 - 4.4.0, 4.4.2 - 5.2.3
Question :
foreach
i should be getting AAAA
but not getting that in the current PHP
stable versionNote* I know i can simply use print $var
but the from PHP DOC
current — Return the current element in an array The current() function simply returns the value of the array element that's currently being pointed to by the internal pointer. It does not move the pointer in any way. If the internal pointer points beyond the end of the elements list or the array is empty, current() returns FALSE.
Update 1 - New Observation
Thanks to Daniel Figueroa : Just by wrapping current
in a function you get different result
foreach ( $list as $var ) { print(item($list)); } function item($list) { return current($list); }
Output ( Demo )
BCDA // What the hell
Question :
foreach
output ? Update 2
$list = array("A","B","C","D"); item2($list); function item2($list) { foreach ( $list as $var ) { print(current($list)); } }
Output ( See Demo )
AAAA // No longer BBBB when using a function
Question :
AAAA
outside and BBBB
in a function in most PHP version The PHP foreach Loop The foreach loop works only on arrays, and is used to loop through each key/value pair in an array.
You can't make JavaScript's forEach() function return a custom value. Using return in a forEach() is equivalent to a continue in a conventional loop.
C#'s foreach loop makes it easy to iterate over elements. This loop works with any collection object that implements IEnumerable<T> . That interface defines one method: GetEnumerator() , which returns an enumerator to step through a collection of values.
Why does it start with B?
Since 5.2 foreach
(reliably) advances the array pointer before the loop body starts. See also the FE_RESET
opcode.
$list = array("A", "B", "C","D"); foreach ($list as $var) { break; } var_dump(current($list));
Output:
B
This may have something to with how the ZEND_OP_DATA
pseudo opcode works (which isn't really documented).
Why does current()
keep giving the same value?
Before the loop starts, foreach
creates an internal reference to the array that you're looping over. Once inside the loop, whenever the array variable is modified or passed by reference, the internal reference is disassociated from the variable by making a copy of the array structure (but not the elements). This copied value retains the array pointer (which had earlier been modified by the loop initialization).
This behaviour is also exhibited with a more destructive unset()
operation:
$list = array('A', 'B', 'C', 'D'); foreach ($list as $key => $val) { echo $val; unset($list[1], $list[2], $list[3]); } echo "\n", print_r($list, true), "\n";
Output:
ABCD Array ( [0] => A )
Passing loop variable to a function
This is another interesting scenario:
$list = array('A', 'B', 'C', 'D'); function itm($arr) { return current($arr); } foreach ($list as $item) { print itm($list); } var_dump(current($list));
Output:
BCDA bool(false)
This time, the array is passed by value and thus its array structure is copied (not the elements) into the function's $arr
parameter. Unlike the previous example, there's no disassociation between the loop's internal reference and the $list
symbol because the copy takes place in the function scope.
What about the last "A"
?
This is by far the most mystifying behaviour of foreach
and can only be witnessed under these circumstances. In the last loop iteration, the array pointer is seemingly rewound to the first item; seemingly because at the end of the loop it obviously points beyond the end of the elements (as you can see from the last line of the output).
This may have something to do with the SWITCH_FREE
opcode that's executed at the end of a foreach
.
So why does placing foreach
in a function make it different?
Observe the following code:
function item2($arr) { foreach ($arr as $var) { print(current($arr)); } var_dump(current($arr)); } $list = array("A","B","C","D"); item2($list);
Output:
AAAA string(1) "A"
In this case, the internal reference of the foreach
is initialized with a copy of the array (because it has a refcount > 1) and thus creates an immediate disassociation from the $arr
symbol.
Can it get worse?
Of course! You can get even whackier results when you start using references or nest multiple foreach
loops on the same variable.
So how can I get consistent results?
Use Iterators
or don't rely on getting a consistent value from referencing the array variable during a foreach
operation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With