foreach最常用且语义清晰,但循环中修改键名或删除元素会导致跳过后续项;安全做法是先收集操作键再统一处理;for仅适用于连续数字索引数组。

foreach 循环最常用,但别在循环里改键名
绝大多数场景直接用 foreach 就够了,它自动解包键值,不改变原数组内部指针,语义也最清晰。但要注意:如果在循环体里用 unset() 删除当前元素,或用 $arr[$key] = $new_val 覆盖值,不会报错,但后续迭代可能跳过某些元素——因为 PHP 的数组内部哈希表结构在遍历时被修改后,遍历器没做实时重同步。
常见错误现象:foreach ($arr as $k => $v) 中执行 unset($arr[$k]),结果漏掉下一个键;或者边循环边 $arr[] = ...,新追加的元素不一定被遍历到。
- 安全做法:需要增删时,先收集要操作的键,循环结束后再统一处理
- 只读遍历?放心用
foreach,性能比for和while都好 - 想同时改值又不影响遍历?用引用:
foreach ($arr as &$v) { $v *= 2; },但记得循环完unset($v)防止意外引用残留
for 循环适合已知索引范围的数值数组
for 不是万能替代品,它依赖数组有连续、从 0 开始的整数键。一旦键不规则(比如 [0, 1, 5, 10] 或字符串键),count($arr) 返回长度,但 $i 下标可能根本不存在,导致 Notice 错误或逻辑跳空。
使用场景:处理 range() 生成的数组、数据库查询结果用 mysqli_fetch_all(MYSQLI_NUM) 得到的纯数字索引结果。
立即学习“PHP免费学习笔记(深入)”;
- 必须确保
$i始终落在有效键范围内,建议配合isset($arr[$i])检查 - 不要用
for ($i = 0; $i ——每次迭代都调用 <code>count(),性能差;改成$len = count($arr); for ($i = 0; $i - 遇到稀疏数组(如键为
0, 100, 200),优先选foreach或array_keys()配合for
while + each() 已废弃,别再用
each() 在 PHP 7.2+ 被标记为废弃,PHP 8.0+ 直接移除。它返回一个包含 key、value、0、1 四个键的数组,还要手动调用 next() 推进指针,写法啰嗦且易出错。
错误示例:while (list($k, $v) = each($arr)) { ... } 在 PHP 8 运行会报 Uncaught Error: Call to undefined function each()。
- 所有旧项目里看到
each(),必须替换成foreach - 如果真需要“手动控制指针”,用
reset()/current()/key()/next()组合,但极少有必要 - 注意
current()返回 false 可能是值为false,不是遍历结束,得用key() === null判断终点
array_walk() 适合带上下文的批量处理
array_walk() 的核心价值不是遍历本身,而是能传额外参数进回调函数,且默认以引用方式操作值(可选)。它比 foreach 多一层函数调用开销,但语义上更强调“对每个元素执行某项操作”。
典型场景:给日志数组每项添加时间戳字段、把用户列表中所有邮箱转小写并过滤空值。
- 修改值必须显式声明引用:
array_walk($arr, function(&$v) { $v = trim($v); }),否则改的是副本 - 第三个参数会作为回调函数的第三个实参传入,适合传配置、DB 连接等上下文
- 不支持关联键直接访问,如果需要键和值,用
array_walk($arr, function($v, $k) { ... }),但注意顺序不能反 - 返回值永远是
true,别指望它返回新数组——要生成新数组用array_map()
foreach,剩下 10% 看需求是否涉及键值联动、上下文传递或严格索引控制。最容易被忽略的是引用残留和键被动态修改时的遍历一致性——这两点不踩坑,代码就稳了一大半。









