views:

41

answers:

3

Recently I experienced this weird problem:

while(list($key, $value) = each($array))

was not listing all array values, where replacing it with...

foreach($array as $key => $value)

...worked perfectly.

And, I'm curious now.. what is the difference between those two?

+10  A: 

Had you previously traversed the array? each() remembers its position in the array, so if you don't reset() it you can miss items.

reset($array);
while(list($key, $value) = each($array))

For what it's worth this method of array traversal is ancient and has been superseded by the more idiomatic foreach. I wouldn't use it unless you specifically want to take advantage of its one-item-at-a-time nature.

array each ( array &$array )

Return the current key and value pair from an array and advance the array cursor.

After each() has executed, the array cursor will be left on the next element of the array, or past the last element if it hits the end of the array. You have to use reset() if you want to traverse the array again using each.

(Source: PHP Manual)

John Kugelman
Thanks a bunch! Didn't knew that there's such a huge difference.
Tom
+1  A: 

If you passed each an object to iterate over, the PHP manual warns that it may have unexpected results.

What exactly is in $array

Dan McGrath
+1  A: 

Well, one difference is that each() will only work on arrays (well only work right). foreach will work on any object that implements the traversable interface (Which of course includes the built in array type).

There may be a micro-optimization in the foreach. Basically, foreach is equivilant to the following:

$array->rewind();
while ($array->valid()) {
   $key = $array->key();
   $value = $array->current();
   // Do your code here
   $array->next();
}

Whereas each basically does the following:

$return = $array->valid() ? array($array->key(), $array->current()) : false;
$array->next();
return $return;

So three lines are the same for both. They are both very similar. There may be some micro-optimizations in that each doesn't need to worry about the traversable interface... But that's going to be minor at best. But it's also going to be offset by doing the boolean cast and check in php code vs foreach's compiled C... Not to mention that in your while/each code, you're calling two language constructs and one function, whereas with foreach it's a single language construct...

Not to mention that foreach is MUCH more readable IMHO... So easier to read, and more flexible means that -to me- foreach is the clear winner. (that's not to say that each doesn't have its uses, but personally I've never needed it)...

ircmaxell
+1 Great detail
John Kugelman
Artefacto
There's another problem with your answer. Arrays don't implement the `Traversable` interface; they're not even objects (try to build an `IteratorIterator` with an array, which has `Traversable` type hint). For `foreach` purposes, they behave like one, but in some cases, you have to use `ArrayIterator` to convert it to a traversable object.
Artefacto
The internal Array object does implement `Traversable`. You cannot use it in place of a iterator because it does not implement `Iterator` or `IteratorAggregate`... But internally, it does function the same...
ircmaxell
@ircmaxell I'm afraid you're mistaken. Arrays are not objects. There is no `Array` class as you can easily see by checking the return value of `class_exists("array")`.
Artefacto