for循环适合控制步数、倒序或跳步遍历,需手动管理索引;foreach适合遍历键值对、对象属性,默认按值拷贝,修改原数组需引用;性能差异取决于是否缓存count();初学者易忽略快照行为、键非连续性及引用陷阱。

for 循环适合“我要控制第几步”
当你需要明确知道当前是第几次循环、要倒着遍历、跳着走(比如每次加2)、或者循环次数和数组长度无关时,for 是唯一自然的选择。它不依赖数组结构,只认数字逻辑。
- 必须手动管理索引变量,比如
$i,且容易写错边界(还是?) - 如果直接在条件里写
count($arr),每次迭代都调用一次——小数组看不出问题,大数组会拖慢速度 - 遍历稀疏数组(比如
unset($arr[1])后的[0 => 'a', 2 => 'c'])会报Notice: Undefined offset,因为$arr[1]已不存在 - 想修改原数组元素?可以,
$arr[$i] = 'new'直接生效,无需额外语法
for ($i = 0, $len = count($fruits); $i < $len; $i++) {
echo $fruits[$i] . "\n";
}
foreach 循环适合“我只要把每个东西拿出来看看”
foreach 不关心“第几个”,只关心“这个值是什么”“它的键叫什么”。它是为数组和对象量身定制的遍历器,不是通用计数器。
- 自动跳过被
unset的键,不会触发Notice - 天然支持关联数组,
foreach ($arr as $key => $value)一行就拿到键值对 - 默认按值拷贝,修改
$value不会影响原数组;要改原数组,得加引用:foreach ($arr as &$value) - 遍历对象时,
foreach能直接读取 public 属性,for完全做不到(除非先转成数组)
$user = ['name' => '张三', 'age' => 28];
foreach ($user as $field => $val) {
echo "$field: $val\n"; // name: 张三, age: 28
}
性能差异真有那么大?看你怎么写
说 foreach “一定比 for 快”是误导。真实差距取决于写法:
- 如果你在
for里缓存了count()(如上例),两者性能几乎持平 - 但若漏掉缓存,
for ($i = 0; $i 会让 PHP 每次都重新算长度,开销翻倍 -
foreach内部走哈希表的next指针,不查 hash,所以对常规遍历更轻量 - 反过来,如果要做反向遍历(从末尾往前处理),
for ($i = count($arr)-1; $i >= 0; $i--)更直接;用foreach就得先array_reverse(),多一次内存拷贝
初学者最容易踩的三个坑
不是语法记不住,而是没意识到这些隐含行为:
立即学习“PHP免费学习笔记(深入)”;
-
foreach遍历时,原数组被“快照”锁定:循环中用unset()或array_push()修改数组,后续迭代可能跳项或重复——PHP 7.4+ 会报Warning: Cannot modify... -
for假设索引连续,但 PHP 数组本质是有序哈希表,array_keys($arr)才是真实键列表,别硬套$i当键用 - 混淆“修改变量”和“修改原数组”:在
foreach ($arr as $v)中改$v,原数组不变;加&$v才变,但忘了 unset 引用会导致后续意外修改(常见于函数内多次 foreach)
for,掏口袋用 foreach。别的都是细节。











