最近我遇到了这个奇怪的问题:
while(list($key, $value) = each($array))
之前代码没有列出所有的数组值,在使用替换后...
foreach($array as $key => $value)
...完美地工作了。
而且,我现在很好奇..这两者之间有什么区别?
最近我遇到了这个奇怪的问题:
while(list($key, $value) = each($array))
之前代码没有列出所有的数组值,在使用替换后...
foreach($array as $key => $value)
...完美地工作了。
而且,我现在很好奇..这两者之间有什么区别?
您之前遍历过这个数组吗?each()
会记住它在数组中的位置,所以如果您不reset()
它,就可能错过一些元素。
reset($array);
while(list($key, $value) = each($array))
值得一提的是,这种遍历数组的方法非常古老,已被更具惯用性的 foreach 取代。除非你明确想要利用它一次只处理一个元素的特性,否则不建议使用。
array each ( array &$array )
从数组中返回当前键值对并将数组光标向前移动。
执行完
each()
后,数组光标将停留在下一个数组元素上,如果到达数组结尾,则停留在最后一个元素的后面。如果要再次使用each
遍历数组,则需要使用reset()
重置数组光标。
(来源:PHP 手册)
while each
是从 while
块内部向 $array
添加元素的好方法。 - The Thirsty Ape区别之一是each()
只能在数组上使用(而且只有在正确使用时才会生效)。foreach
可以在任何实现traversable
接口的对象上使用(这当然包括内置的数组类型)。
可能有一个微观优化需要使用 foreach。基本上,foreach等价于以下内容:
$array->rewind();
while ($array->valid()) {
$key = $array->key();
$value = $array->current();
// Do your code here
$array->next();
}
而 each
基本上执行以下操作:
$return = $array->valid() ? array($array->key(), $array->current()) : false;
$array->next();
return $return;
对于它们来说,这三行代码是相同的。它们非常相似。也许each
不需要考虑traversable
接口等微小优化...但这最多只会是一些小的改善。但是与foreach
编译的C语言相比,在php代码中执行布尔转换和检查也将被抵消...更不用说在你的while / each
代码中,你要调用两个语言结构和一个函数,而foreach
只有一个语言结构...
更不用说,在我看来,foreach
要容易阅读得多...因此,易于阅读和灵活性更高意味着对我来说foreach
是明显的赢家。(这并不是说each
没有其用处,但个人从未需要过它)...
foreach
会像在数组的副本中操作一样行事。例如,如果您在迭代过程中更改原始数组的元素,则foreach
仍将给您原始数组。只有在开始使用引用(例如foreach($array as &$v){}
)时,此行为才会更改,因为在这种情况下,您正在表明要更改数组。请参见http://codepad.viper-7.com/bGaIqc - ArtefactoTraversable
接口;它们甚至不是对象(试着用具有 Traversable
类型提示的数组构建一个 IteratorIterator
,就会发现)。对于 foreach
的目的,它们的行为类似于对象,但在某些情况下,你必须使用 ArrayIterator
将其转换为可遍历的对象。 - ArtefactoTraversable
接口。但是你不能将其用作迭代器,因为它没有实现Iterator
或IteratorAggregate
接口... 但在内部,它的功能是相同的... - ircmaxellclass_exists("array")
的返回值,你会发现根本不存在 Array
类。 - Artefacto警告! 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 (例如删除元素)或其他密集型映射/列表/字典过滤构建应用程序的开发人员可以证明我在这里所说的重要性。
如果您不理解这个答案,它总有一天会让你后悔。
foreach($array as $key => &$value) {}
,它会给你一个元素的引用。 - Konstantin Bodniaeach()
。 - Xeoncrossprint $i
"的输出以了解区别。这里重要的是要理解对当前正在迭代的实际数组(each()
)进行修改与对最终输出数组(foreach()
)进行修改的区别。 - Xeoncrosseach
进行迭代,PHP手册警告可能会产生意外的结果。$array
中确切包含什么?
foreach()
适用于96%的所有用例。然而,有时您必须在迭代过程中更改数组本身,这就是each()
的强大之处,因为foreach会在内部复制数组。请参见下面的答案。任何使用libxml的人都可以证明盲目地将foreach用于每种情况的危险性。 - Xeoncrosseach
在PHP 7.2中已被弃用。 - Jeff Puckett