PHP遍历二维数组需嵌套两层foreach:外层取行,内层取列;关联数组须用键名访问并防Undefined index;修改原值需加&引用且遍历后unset;避免内层重复count()或条件中函数调用。

foreach 遍历二维数组的基本写法
PHP 中遍历二维数组,本质是嵌套两层 foreach:外层取行(一维子数组),内层取列(该行中的每个值)。关键不是“能不能”,而是“哪一层用引用、哪一层要防键名混淆”。
常见错误是直接对二维数组用单层 foreach,结果得到的是子数组本身,不是你想打印的字符串或数字:
$data = [['a', 'b'], ['x', 'y']];
foreach ($data as $row) {
echo $row; // Warning: Array to string conversion
}
- 外层
$row是数组,不能直接 echo - 内层必须再加一层
foreach才能访问具体元素 - 如果需要键名(比如数据库字段名),外层用
foreach ($data as $i => $row),内层用foreach ($row as $k => $v)
带键名的二维关联数组怎么安全遍历
从 mysqli_fetch_all(MYSQLI_ASSOC) 或 json_decode($json, true) 得到的二维数组通常是关联结构,键名不确定,不能假设下标是 0/1。这时候硬写 $row[0] 极易出错。
正确做法是始终用键名访问,或先检查键是否存在:
立即学习“PHP免费学习笔记(深入)”;
$users = [
['id' => 1, 'name' => 'Alice'],
['id' => 2, 'name' => 'Bob']
];
foreach ($users as $user) {
echo $user['id'] . ': ' . ($user['name'] ?? 'N/A') . "\n";
}
- 用
??运算符避免Undefined index警告 - 不要依赖顺序,
foreach遍历关联数组时键名才是唯一可靠依据 - 如果某些子数组缺失某个键(如部分记录没有
email),必须显式判断,不能跳过
修改原数组值时为什么必须加 & 引用
默认情况下,foreach 中的变量是原数组元素的副本。想在遍历中直接改二维数组里的值,不加引用就白忙活。
$matrix = [[1, 2], [3, 4]];
foreach ($matrix as &$row) { // 注意这里的 &
foreach ($row as &$cell) { // 内层也要 &
$cell *= 2;
}
}
// $matrix 现在是 [[2, 4], [6, 8]]
unset($cell); // 必须 unset,否则 $cell 仍引用最后一个元素,可能污染后续代码
unset($row); // 同理
- 漏掉
&,所有赋值都只作用在副本上,原数组不变 - 内层循环结束后必须
unset($cell),否则下次循环或后续代码中$cell仍指向旧内存,导致意外覆盖 - PHP 7.4+ 允许在
foreach中直接写foreach ($arr as &$v),但嵌套时仍需谨慎处理引用生命周期
性能敏感场景下避免重复计算子数组长度
如果二维数组很大(比如上千行),又在内层循环里反复调用 count($row) 或 sizeof($row),会轻微拖慢速度——因为 PHP 每次都重新算长度。
- 提前把
count($row)存进变量,尤其在for循环中更明显;但foreach本身不依赖长度,所以影响有限 - 真正要注意的是:别在
foreach条件里放函数调用,比如foreach (get_data() as $row)—— 这会让函数被反复执行 - 如果数据源来自 DB 查询,优先用流式 fetch(如
mysqli_use_result())而非一次性fetch_all加载全部到内存
二维数组遍历本身开销不大,真正卡住的往往是里面混了未缓存的函数调用、没关的资源句柄,或者忘了 unset 引用变量。



















