【发布时间】:2010-12-23 13:27:22
【问题描述】:
在 php 中遍历数组的速度最快的是哪一个?或者是否存在另一个对于遍历数组也更快的方法?
【问题讨论】:
标签: php arrays for-loop while-loop foreach
在 php 中遍历数组的速度最快的是哪一个?或者是否存在另一个对于遍历数组也更快的方法?
【问题讨论】:
标签: php arrays for-loop while-loop foreach
即使有任何不同,那差异也会很小,根本不重要。
如果你有一个对数据库的查询,与循环迭代结果相比,这将花费很长时间,以至于for vs foreach vs while 的永恒争论不会改变任何事情-- 至少如果你有合理数量的数据。
所以,使用:
在考虑这种微优化之前,您可以/应该优化许多其他事情。
如果你真的想要一些数字(即使只是为了好玩),你可以做一些基准测试并在实践中查看结果。
【讨论】:
进行基准测试。
没有重大的“性能”差异,因为差异位于逻辑内部。
【讨论】:
正确使用,while 是最快的,因为它每次迭代只能进行一次检查,将一个 $i 与另一个 $max 变量进行比较,并且在循环之前(设置 $max 除外)或循环期间($ 除外)没有额外的调用i++; 本质上是在任何循环语句中完成的)。
当你开始滥用它时(比如 while(list..) ),你当然最好使用 foreach,因为每个函数调用都不会像 foreach 中包含的那样优化(因为它是预先优化的)。
即便如此,array_keys() 仍为您提供与 foreach 相同的可用性,而且速度更快。 除此之外,如果您喜欢二维数组,自制的 2d_array_keys 将使您能够以更快的方式一直使用 foreach (只需尝试在第一个 foreach 中告诉下一个 foreach,最后一个 foreach 有 作为键 --- )。
此外,所有与循环的第一项或最后一项相关的问题都使用 while($i
还有
while ($people_care_about_optimization!==true){
echo "there still exists a better way of doing it and there's no reason to use any other one";
}
【讨论】:
对我来说,我根据这个来选择我的循环:
foreach
在遍历长度未知(或可能未知)的数组时使用。
for
在遍历已设置长度的数组时使用,或者在需要计数器时使用。
while
当您以查找或触发某个标志为明确目的而遍历数组时使用。
现在确实如此,您可以使用类似 FOREACH 循环的 FOR 循环,通过使用 count($array)... 所以最终归结为您的个人偏好/风格。
【讨论】:
while 循环对于使用关联键数组(如果删除数组中的元素则为非连续键)的复杂算法也很有用,并且您需要将当前值与前一个值进行比较/下一个值。您可以使用foreach 循环将前一个值复制到变量中,但您不能使用prev() 或next() 函数,因为foreach 循环不保留对内部数组指针的引用。
一般来说,这三个函数之间没有适用的速度差异。
提供基准测试结果以展示用于迭代 1 to 10,000 中的数组的不同方法的效率。
不同 PHP 版本的基准测试结果:https://3v4l.org/a3Jn4
while $i++: 0.00077605247497559 sec
for $i++: 0.00073003768920898 sec
foreach: 0.0004420280456543 sec
while current, next: 0.024288892745972 sec
while reset, next: 0.012929201126099 sec
do while next: 0.011449098587036 sec //added after terminal benchmark
while array_shift: 0.36452603340149 sec
while array_pop: 0.013902902603149 sec
考虑到count 和while 和for 的个人调用
$values = range(1, 10000);
$l = count($values);
$i = 0;
while($i<$l){
$i++;
}
$l = count($values);
for($i=0;$i<$l;$i++){
}
foreach($values as $val){
}
以下使用while 的示例演示了如何在迭代过程中降低使用效率。
在功能上迭代数组并保持当前位置时; while 的效率大大降低,因为在迭代期间会调用 next() 和 current()。
while($val = current($values)){
next($values);
}
如果数组的当前位置不重要,可以在迭代前调用reset()或current()。
$value = reset($values);
while ($value) {
$value = next($values);
}
do ... while 是一种可以使用的替代语法,也可以与在迭代之前调用 reset() 或 current() 以及将 next() 调用移动到迭代结束时结合使用。
$value = current($values);
do{
}while($value = next($values));
array_shift 也可以在迭代期间调用,但这会对性能产生很大的负面影响,因为array_shift 每次调用时都会重新索引数组。
while($values){
array_shift($values);
}
或者array_reverse 可以在迭代之前调用,同时调用array_pop。这样可以避免调用array_shift时重新索引的影响。
$values = array_reverse($values);
while($values) {
array_pop($values);
}
总之,while、for 和 foreach 的速度不应该是问题,而是在它们内部做了什么来保持阵列的定位。
【讨论】:
请记住,将大量 mysqli_result 预取到一个舒适的数组中可能会引发这样一个问题:使用 for/foreach/while 循环该数组是否更好,但这是一个错误的问题浪费大量内存的解决方案。
所以不喜欢这个:
function funny_query_results($query) {
$results = $GLOBALS['mysqli']->query($query);
$rows = [];
while( $row = $results->fetch_object() ) {
$rows[] = $results;
}
return $rows;
}
$rows = funny_query_results("SELECT ...");
foreach($rows as $row) { // Uh... What should I use? foreach VS for VS while?
echo $row->something;
}
在一个简单的while 中逐一获取每个mysql_result 的直接方法更加优化:
$results = $mysqli->query("SELECT ...");
while( $row = $results->fetch_object() ) {
echo $row->something;
}
【讨论】: