while(list($key, $value) = each($array)) vs. foreach($array as $key => $value)?

71,407

Solution 1

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)

Solution 2

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)...

Solution 3

Warning! Foreach creates a copy of the array so you cannot modify it while foreach is iterating over it. each() still has a purpose and can be very useful if you are doing live edits to an array while looping over it's elements and indexes.

// Foreach creates a copy
$array = [
  "foo" => ['bar', 'baz'],
  "bar" => ['foo'],
  "baz" => ['bar'],
  "batz" => ['end']
];

// while(list($i, $value) = each($array)) { // Try this next
foreach($array as $i => $value) {
  print $i . "\n";
  foreach($value as $index) {
    unset($array[$index]);
  }
}

print_r($array); // array('baz' => ['end'])

Both foreach and while will finish their loops and the array "$array" will be changed. However, the foreach loop didn't change while it was looping - so it still iterated over every element even though we had deleted them.

Update: This answer is not a mistake.

I thought this answer was pretty straight forward but it appears the majority of users here aren't able to appreciate the specific details I mention here.

Developers that have built applications using libdom (like removing elements) or other intensive map/list/dict filtering can attest to the importance of what I said here.

If you do not understand this answer it will bite you some day.

Solution 4

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

What exactly is in $array

Share:
71,407
tomsseisums
Author by

tomsseisums

Updated on March 11, 2020

Comments

  • tomsseisums
    tomsseisums about 4 years

    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?

  • Artefacto
    Artefacto almost 14 years
    It's not exactly the same because foreach will behave as if it's operating in a copy of the array. For instance, if you change an element of the original array during iteration, foreach will still give you the original one. This behavior only changes if you start using references (e.g. foreach ($array as &$v) {}) because in that case you're signaling your intention to change the array. See codepad.viper-7.com/bGaIqc
  • Artefacto
    Artefacto almost 14 years
    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.
  • ircmaxell
    ircmaxell almost 14 years
    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...
  • Artefacto
    Artefacto almost 14 years
    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").
  • The Thirsty Ape
    The Thirsty Ape almost 11 years
    Good comparison. I found that while each is a good way to add elements to $array from within the while block if needed.
  • cram2208
    cram2208 about 9 years
    Very interesting comparison ! What about the performance difference between each method, are they practically the same ?
  • Konstantin Bodnia
    Konstantin Bodnia almost 9 years
    Yes. But you can always use foreach($array as $key => &$value) {} and it will give you a reference to the element.
  • Xeoncross
    Xeoncross over 8 years
    @KonstantinBodnya, you totally missed the point of my answer. If you need to alter the array (not the element) you must use each().
  • Andrew Willis
    Andrew Willis about 8 years
    passing a reference to the element in the array will alter the array.
  • Xeoncross
    Xeoncross about 8 years
    @AndrewWillis, it will alter the element in the array but not the array itself. In other words, you can't do things like remove the element, and thereby alter the actual array of items.
  • Andrew Willis
    Andrew Willis about 8 years
    Apologies, I was thinking about this specifically in my use case, however I would probably use array_filter for removing values from arrays, even if just for clarity.
  • A.L
    A.L about 8 years
    Here are codepad with the 2 different codes: codepad.org/y7kG5MuY codepad.org/8WdC46Os With foreach the values are removed from the $array array. So the array is modified. I don't understand your example.
  • Xeoncross
    Xeoncross about 8 years
    @A.L, look at the "print $i" output to see the difference. The important thing here is to understand about the modification to the actual array currently being iterated over (each()) vs the modification to the final output array (foreach())
  • Tihomir Mitkov
    Tihomir Mitkov over 7 years
    @Xeoncross You have an excellent point here. Shame for others that they can't understand this...