前面两节我们分别讨论了索引数组和关联数组,它们都是一维数组——每个元素存储一个标量值(数字、字符串等)。但在开发里,数据往往不是扁平的。一张表格有行有列,一个部门下面有多个员工,一份问卷里每道题有多个选项。这些“数据里套数据”的结构,就需要用到多维数组。
多维数组就是数组的数组——外层数组的每个元素本身也是一个数组。常见的是二维数组,可以理解为一张表格:外层数组的每个元素代表一行,内层数组代表这一行里的各列数据。三维及以上的数组理论上也可以构造,但代码可读性会明显下降,实际使用频率不高。
二维索引数组:用数字坐标访问数据
二维索引数组外层和内层都用数字索引。适合存储规则的行列数据,比如电子表格、矩阵、坐标网格。
定义方式:
$teamList = array(
array(1, "张明", 28000),
array(2, "李华", 32000),
array(3, "王芳", 35000)
);
外层数组有三个元素,每个元素是一个内层数组,分别存着编号、姓名、薪资。
用嵌套for循环遍历:
<?php
$teamList = array(
array(1, "张明", 28000),
array(2, "李华", 32000),
array(3, "王芳", 35000)
);
// 外层循环遍历行
for ($i = 0; $i < count($teamList); $i++) {
// 内层循环遍历当前行的每一列
for ($j = 0; $j < count($teamList[$i]); $j++) {
echo $teamList[$i][$j] . " ";
}
echo "<br/>";
}
?>
输出:
1 张明 28000
2 李华 32000
3 王芳 35000
$teamList[$i][$j]这个写法里,第一个方括号[$i]定位外层数组的行,第二个[$j]定位这一行里的具体列。先找行再找列,顺序不能乱。
用嵌套foreach遍历同样内容:
<?php
$teamList = array(
array(1, "张明", 28000),
array(2, "李华", 32000),
array(3, "王芳", 35000)
);
foreach ($teamList as $row) {
foreach ($row as $cell) {
// 用sprintf格式化数字列对齐
echo sprintf("%-8s", $cell);
}
echo "<br/>";
}
?>
foreach版本不需要手动管理索引变量,代码更简洁。sprintf("%-8s", $cell)让每个单元格占8个字符宽度,输出排列得更整齐。
访问单个元素:
<?php
$scoreTable = array(
array(85, 90, 78),
array(92, 88, 95),
array(76, 82, 80)
);
// 访问第2行第3列的元素(注意索引从0开始)
echo "第2行第3列的成绩:" . $scoreTable[1][2];
?>
输出:第2行第3列的成绩:95
$scoreTable[1][2]中,[1]是行索引(第二行),[2]是列索引(第三列)。因为索引从0开始,第二行是索引1,第三列是索引2。
二维关联数组:用有意义的键名组织数据
当表格的列有明确的字段名时,二维关联数组比纯数字索引更易读。外层可以用数字索引或关联键名,内层用关联数组描述每条记录的属性。
定义方式:
$employeeList = array(
"员工A" => array("部门" => "技术部", "职位" => "工程师", "工龄" => 3),
"员工B" => array("部门" => "产品部", "职位" => "产品经理", "工龄" => 5),
"员工C" => array("部门" => "设计部", "职位" => "设计师", "工龄" => 2)
);
外层键是员工姓名,内层键是属性名(部门、职位、工龄)。
遍历并访问内层数据:
<?php
$employeeList = array(
"员工A" => array("部门" => "技术部", "职位" => "工程师", "工龄" => 3),
"员工B" => array("部门" => "产品部", "职位" => "产品经理", "工龄" => 5),
"员工C" => array("部门" => "设计部", "职位" => "设计师", "工龄" => 2)
);
foreach ($employeeList as $name => $info) {
echo "<strong>{$name}</strong><br/>";
foreach ($info as $field => $value) {
echo " {$field}:{$value}<br/>";
}
echo "<br/>";
}
?>
输出:
员工A
部门:技术部
职位:工程师
工龄:3
员工B
部门:产品部
职位:产品经理
工龄:5
员工C
部门:设计部
职位:设计师
工龄:2
外层foreach拿到员工姓名(键)和对应的属性数组(值),内层foreach再拆开属性数组里的每个键值对。
访问单个元素的指定属性:
<?php
$productList = array(
"商品A" => array("名称" => "机械键盘", "价格" => 599, "库存" => 120),
"商品B" => array("名称" => "无线鼠标", "价格" => 199, "库存" => 300),
"商品C" => array("名称" => "显示器", "价格" => 2299, "库存" => 45)
);
// 访问商品B的价格
echo "商品B的价格:¥" . $productList["商品B"]["价格"];
?>
输出:商品B的价格:¥199
两个方括号连续使用:第一个定位外层键"商品B",第二个定位内层键"价格"。
递归遍历任意深度的多维数组
有时候数组的嵌套层级不是固定的——比如文件目录结构(文件夹里套文件夹,深度不定),或者树形分类(大类套小类,小类套子类)。这种场景用固定层数的嵌套循环已经不够了,需要递归函数来处理。
递归遍历的思路是:遍历数组的每个元素,如果某个元素的值本身又是一个数组,就用同一个函数递归处理它,直到遇到非数组的值才直接输出。
<?php
// 递归遍历函数
function traverseArray($arr) {
foreach ($arr as $key => $value) {
if (is_array($value)) {
// 值是数组,递归调用自己继续深入
echo "进入层级:{$key}<br/>";
traverseArray($value);
} else {
// 值不是数组,直接输出键值对
echo "{$key} => {$value}<br/>";
}
}
}
// 一个嵌套结构不规则的数组
$nestedData = array(
"分类A" => array(
"子类A1" => "内容A1",
"子类A2" => array(
"深层A2a" => "内容A2a",
"深层A2b" => "内容A2b"
)
),
"分类B" => array(
"子类B1" => "内容B1",
"子类B2" => "内容B2"
)
);
traverseArray($nestedData);
?>
输出大致是:
进入层级:分类A
子类A1 => 内容A1
进入层级:子类A2
深层A2a => 内容A2a
深层A2b => 内容A2b
分类B
进入层级:分类B
子类B1 => 内容B1
子类B2 => 内容B2
is_array()函数判断当前值是否还是数组,如果是就递归进入,不是就打印。这个递归逻辑对嵌套层数没有硬性限制,只要PHP内存和递归深度允许,就能一直深入下去。
本节课程知识要点
PHP多维数组是处理结构化数据的重要工具,以下核心点需要理解透彻:
-
多维数组是“数组的数组”,外层数组的每个元素本身也是一个数组。最常见的是二维数组。
-
二维索引数组适合行列整齐的表格数据,用
$arr[行索引][列索引]访问,适合用嵌套for或foreach遍历。 -
二维关联数组更适合有语义的表格数据,行和列都有名字,用
$arr['行键']['列键']访问,遍历用嵌套foreach配合=>。 -
访问元素时,方括号的顺序从外到内。先定位外层,再逐层深入。
-
嵌套层数不固定时用递归遍历,
is_array()判断是否需要继续深入,递归逻辑和之前学的递归函数原理一致。
多维数组的适用场景和选择建议
多维数组在以下场景里用得比较多:
-
表格型数据:查询数据库返回的多行记录集,每行是一个关联数组,所有行组成一个二维关联数组。
-
树形结构:组织架构、分类树、菜单层级,外层键是节点名,值可能是子节点的数组。
-
表单数据:HTML表单里用
name="items[]"这种数组风格的字段,提交到PHP后$_POST['items']就是一个二维数组。 -
JSON解析结果:API返回的嵌套JSON,
json_decode($json, true)解析成多维关联数组。
个人经验分享: 在代码号学习编程的过程中,二维数组是使用频率很高的结构,但三维及以上就得警惕了。数组嵌套超过三层,代码的复杂度和可读性会显著变差。遇到需要深层嵌套的情况,我会考虑是不是应该把内层数据抽出来定义成独立的类或结构,用面向对象的方式去组织。数组虽然灵活,但过度嵌套会让维护变得困难。
主观建议: 二维数组是“够用且清晰”的合理边界。如果发现自己在写$arr['a']['b']['c']['d']这样的四层访问路径,值得停下来想一想:能不能把其中一部分抽象成独立的数据结构?多维数组是个比较好用的工具,但和所有工具一样,用对场景比用对语法更重要。
PHP多维数组从概念上就是“数组套数组”,理解起来并不复杂。重点是掌握用嵌套循环遍历二维结构、用方括号逐层访问元素、以及用递归应对深度不固定的场景。在后续学习数组排序、合并、过滤等函数时,多维数组的这些遍历和访问技巧会反复用到。