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

Php while(list($key,$value)=each($array))vs.foreach($array as$key=>;$value)?,php,arrays,loops,foreach,while-loop,Php,Arrays,Loops,Foreach,While Loop,最近我遇到了一个奇怪的问题: while(list($key, $value) = each($array)) 未列出所有数组值,其中将其替换为 foreach($array as $key => $value) …工作得很好 而且,我现在很好奇。。这两者之间的区别是什么?您以前是否遍历过数组each()记住它在数组中的位置,因此如果不reset()它,您可能会错过项目 reset($array); while(list($key, $value) = each($array)) 值

最近我遇到了一个奇怪的问题:

while(list($key, $value) = each($array))
未列出所有数组值,其中将其替换为

foreach($array as $key => $value)
…工作得很好


而且,我现在很好奇。。这两者之间的区别是什么?

您以前是否遍历过数组
each()
记住它在数组中的位置,因此如果不
reset()
它,您可能会错过项目

reset($array);
while(list($key, $value) = each($array))
值得一提的是,这种数组遍历方法非常古老,已经被更为惯用的foreach方法所取代。我不会使用它,除非你特别想利用它一次一项的特性

数组每个(数组和$array)

从数组返回当前键和值对,并前进数组光标

执行
each()
后,数组光标将留在数组的下一个元素上,如果到达数组的末尾,则会超过最后一个元素。如果要使用
每个
再次遍历数组,必须使用
reset()


(来源:)

如果向每个对象传递了一个要迭代的对象,PHP手册会警告它可能会产生意外的结果


$array

的具体内容是什么呢?好吧,一个区别是
each()
只能在数组上工作(好吧,只能正常工作)
foreach
将处理实现接口的任何对象(当然包括内置数组类型)

foreach中可能存在微观优化。基本上,foreach等同于以下内容:

$array->rewind();
while ($array->valid()) {
   $key = $array->key();
   $value = $array->current();
   // Do your code here
   $array->next();
}
$return = $array->valid() ? array($array->key(), $array->current()) : false;
$array->next();
return $return;
然而,
每个
基本上都有以下功能:

$array->rewind();
while ($array->valid()) {
   $key = $array->key();
   $value = $array->current();
   // Do your code here
   $array->next();
}
$return = $array->valid() ? array($array->key(), $array->current()) : false;
$array->next();
return $return;
所以这三条线对两者都是一样的。它们都非常相似。可能有一些微优化,每个
都不需要担心
可遍历的
接口。。。但这充其量只是个小问题。但它也将通过在php代码中执行布尔强制转换和检查来抵消,而不是使用foreach
的编译C。。。更不用说在
while/each
代码中,您调用的是两种语言结构和一个函数,而在
foreach
中,它是一种单一的语言结构


更不用说,
foreach
的可读性更高。。。因此更容易阅读,更灵活意味着——对我来说,
foreach
显然是赢家。(这并不是说每个代码都没有它的用途,但就我个人而言,我从来都不需要它)…

警告Foreach创建数组的副本,因此在Foreach对其进行迭代时,您不能对其进行修改
each()
仍然有它的用途,如果在数组的元素和索引上循环时对数组进行实时编辑,它会非常有用

// 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'])
foreach
while
都将完成循环,数组“
$array
”将被更改。然而,foreach循环在循环时并没有改变,所以它仍然在每个元素上迭代,即使我们已经删除了它们

更新:这个答案不是错误。 我认为这个答案非常直截了当,但这里的大多数用户似乎无法理解我在这里提到的具体细节

使用libdom(比如删除元素)或其他密集的map/list/dict过滤构建应用程序的开发人员可以证明我在这里所说的内容的重要性


如果你不理解这个答案,总有一天它会咬你。

这不完全一样,因为
foreach
的行为就像它在数组的副本中运行一样。例如,如果在迭代过程中更改原始数组的一个元素,
foreach
仍将为您提供原始数组。只有当您开始使用引用(例如,
foreach($array as&$v){}
)时,此行为才会发生变化,因为在这种情况下,您发出了更改数组的信号。你的答案还有一个问题。数组不实现可遍历的
接口;它们甚至不是对象(尝试用数组构建一个
iteratoriator
,该数组具有
Traversable
类型提示)。出于
foreach
目的,它们的行为类似于一个,但在某些情况下,您必须使用
ArrayIterator
将其转换为可遍历对象。内部数组对象确实实现了
traversable
。您不能使用它来代替迭代器,因为它没有实现
iterator
IteratorAggregate
。。。但在内部,它的功能是一样的……恐怕你弄错了。数组不是对象。通过检查
class\u exists(“Array”)
的返回值,可以很容易地看到没有
Array
类。比较好。我发现
while each
是从
while
块中添加元素到
$array
的好方法(如果需要)。非常有趣的比较!每种方法之间的性能差异如何?它们实际上是相同的吗?是的。但是您可以始终使用
foreach($key=>数组和$value){}
,它将为您提供对元素的引用。@KonstantinBodnya,您完全没有理解我的答案。如果需要更改数组(而不是元素),则必须使用
each()
。传递对数组中元素的引用将更改数组。@AndrewWillis,它将更改数组中的元素,但不会更改数组本身。换句话说,您不能执行诸如删除元素之类的操作,从而改变项目的实际数组。@A.L,请查看“
print$i
”输出以查看差异。这里重要的是要了解对当前迭代的实际数组的修改(
each()
)与对最终输出数组的修改(
foreach()
)之间的关系。注意:
foreach()
适用于96%的用例。但是,有时您必须在i期间更改数组本身