PHP: 数组进阶与排序
上一课你知道了数组是什么、怎么创建和遍历。这节课进入 PHP 数组的真正威力区——数不尽的数组处理函数让你的代码简洁到令人发指。
1. 数组合并
PHP
<?php
$arr1 = ["a" => "苹果", "b" => "香蕉"];
$arr2 = ["b" => "蓝莓", "c" => "樱桃"];
// array_merge:合并,同名键后者覆盖前者
$merged = array_merge($arr1, $arr2);
// ["a" => "苹果", "b" => "蓝莓", "c" => "樱桃"]
// + 运算符:合并,同名键前者优先(保留左边)
$union = $arr1 + $arr2;
// ["a" => "苹果", "b" => "香蕉", "c" => "樱桃"]
// 注意 "b" 保留了左边的 "香蕉"
// array_merge 对索引数组会重排索引
$nums1 = [1, 2, 3];
$nums2 = [4, 5];
print_r(array_merge($nums1, $nums2)); // [1,2,3,4,5](重排索引)
print_r($nums1 + $nums2); // [1,2,3](+ 不重排)
?>
array_merge |
+ 运算符 |
|
|---|---|---|
| 同名字符串键 | 后者覆盖前者 | 前者覆盖后者 |
| 索引数组 | 重排索引 | 不重排,忽略已有索引 |
💡 提示: 合并用户提交的数据和默认配置用
$config = array_merge($defaults, $userInput);——用户覆盖默认值。
2. 数组差集与交集
PHP
<?php
$a = [1, 2, 3, 4, 5];
$b = [4, 5, 6, 7];
// array_diff:在 $a 中但不在 $b 中的值
print_r(array_diff($a, $b)); // [1, 2, 3]
// array_intersect:在 $a 中且在 $b 中的值
print_r(array_intersect($a, $b)); // [4, 5]
?>
3. 数组键值操作
PHP
<?php
$user = ["name" => "小明", "age" => 25, "city" => "北京"];
// array_keys:获取所有键
print_r(array_keys($user));
// ["name", "age", "city"]
// array_values:获取所有值(重置为索引数组)
print_r(array_values($user));
// ["小明", 25, "北京"]
// 检查键或值
var_dump(array_key_exists("age", $user)); // bool(true)
var_dump(in_array("上海", $user)); // bool(false)
// array_search:查找值对应的键
$key = array_search(25, $user);
echo $key; // "age"
?>
4. array_filter — 过滤数组
根据回调函数返回的 true/false 来决定保留哪些元素:
PHP
<?php
$numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// 只保留偶数
$even = array_filter($numbers, function($n) {
return $n % 2 == 0;
});
print_r($even); // [1=>2, 3=>4, 5=>6, 7=>8, 9=>10]
// 注意键被保留了!用 array_values 重置:
print_r(array_values($even)); // [2, 4, 6, 8, 10]
// 不带回调时:过滤掉等于 false 的值
$mixed = [0, "hello", "", null, false, "world", []];
$filtered = array_filter($mixed);
print_r($filtered); // [1=>"hello", 5=>"world"]
?>
▶ 示例:用 array_filter 过滤空数据
PHP
<?php
// 过滤用户提交的表单(去掉空字段)
$form = [
"name" => "小明",
"email" => "",
"phone" => null,
"city" => "北京",
"comment" => false
];
$cleaned = array_filter($form, function($val) {
return $val !== "" && $val !== null && $val !== false;
});
print_r($cleaned);
// ["name"=>"小明", "city"=>"北京"]
?>
5. array_map — 对每个元素应用函数
PHP
<?php
$numbers = [1, 2, 3, 4, 5];
// 每个数乘 2
$doubled = array_map(function($n) {
return $n * 2;
}, $numbers);
print_r($doubled); // [2, 4, 6, 8, 10]
// 用内置函数
$squares = array_map(fn($n) => $n * $n, $numbers);
print_r($squares); // [1, 4, 9, 16, 25]
// 多个数组同时处理
$a = [1, 2, 3];
$b = [4, 5, 6];
$sums = array_map(fn($x, $y) => $x + $y, $a, $b);
print_r($sums); // [5, 7, 9]
?>
6. 排序函数全家桶
PHP 有 11 个排序函数,但只需要记住 4 对 + 1 个自定义:
PHP
<?php
$fruits = ["orange", "apple", "banana"];
$ages = ["Peter" => 32, "John" => 28, "Jane" => 35];
// === 按值排序 ===
sort($fruits); // 升序,重建索引 → ["apple","banana","orange"]
rsort($fruits); // 降序,重建索引 → ["orange","banana","apple"]
// === 按值排序,保持键 ===
asort($ages); // 值升序,保持键 → ["John"=>28,"Peter"=>32,"Jane"=>35]
arsort($ages); // 值降序,保持键 → ["Jane"=>35,"Peter"=>32,"John"=>28]
// === 按键排序 ===
ksort($ages); // 键升序 → ["Jane"=>35,"John"=>28,"Peter"=>32]
krsort($ages); // 键降序 → ["Peter"=>32,"John"=>28,"Jane"=>35]
// === 自定义排序 ===
usort($fruits, fn($a, $b) => strlen($a) <=> strlen($b));
// 按字符串长度升序
?>
| 函数 | 排序依据 | 方向 | 保持键? |
|---|---|---|---|
sort |
值 | 升序 | ❌ 重建索引 |
rsort |
值 | 降序 | ❌ |
asort |
值 | 升序 | ✅ |
arsort |
值 | 降序 | ✅ |
ksort |
键 | 升序 | ✅ |
krsort |
键 | 降序 | ✅ |
usort |
自定义 | 自定义 | ❌ |
uasort |
自定义(值) | 自定义 | ✅ |
💡 提示:
asort / ksort 保持键值对应关系,适合关联数组(如成绩单)。sort / rsort 重建索引,适合普通列表。
7. 多维数组
数组中套数组,通常用来存储结构化数据:
PHP
<?php
$students = [
["name" => "张三", "score" => 92, "city" => "北京"],
["name" => "李四", "score" => 85, "city" => "上海"],
["name" => "王五", "score" => 78, "city" => "北京"],
];
// 访问:先外层后内层
echo $students[0]["name"]; // 张三
// 遍历
foreach ($students as $s) {
echo "{$s['name']}: {$s['score']}分<br>";
}
// 用 array_column 提取某一列
$names = array_column($students, "name");
print_r($names); // ["张三", "李四", "王五"]
$scores = array_column($students, "score", "name");
// ["张三"=>92, "李四"=>85, "王五"=>78]
// 第三个参数指定用哪列做键
?>
▶ 示例:多维数组排序
PHP
<?php
$products = [
["name" => "键盘", "price" => 299],
["name" => "鼠标", "price" => 149],
["name" => "显示器", "price" => 1299],
["name" => "鼠标垫", "price" => 29],
];
// 按价格从低到高排序(自定义比较函数)
usort($products, fn($a, $b) => $a["price"] <=> $b["price"]);
foreach ($products as $p) {
echo "{$p['name']}:{$p['price']}元<br>";
}
// 鼠标垫:29元
// 鼠标:149元
// 键盘:299元
// 显示器:1299元
?>
<=> 太空船运算符在这里太适合了——一行代码完成多维数组排序,优雅到极致。
8. 数组解构(PHP 7.1+)
用 [] 或 list() 一次性把数组值赋给多个变量:
PHP
<?php
// 解构索引数组
$info = ["小明", 25, "北京"];
[$name, $age, $city] = $info;
echo $name; // 小明
// 解构关联数组(PHP 7.1+)
$user = ["name" => "小红", "age" => 22];
["name" => $n, "age" => $a] = $user;
echo $n; // 小红
// 选择性提取(PHP 7.1+)
[2 => $city, 0 => $name] = $info;
echo $city; // 北京
?>
❓ 常见问题
Q
array_merge 和 + 运算符怎么选?A 绝大多数场景用
array_merge。处理用户配置覆盖默认值时:$config = array_merge($defaults, $userConfig);——用户设置覆盖默认值。只有在你明确需要"已有键保留"时用 +。Q usort 很强大,但什么时候用它?
A 当你需要按自定义规则排序时——比如按价格排序、按名字长度排序、按多层嵌套的属性排序。usort +
<=> 是一对黄金搭档。Q 多维数组太深了怎么办?
A 超过 3 层嵌套就该考虑是否应该用对象或类来组织数据了。数组适合简单结构,复杂结构用对象更清晰。
📖 小节
array_merge合并数组(后者覆盖),+合并(前者优先)array_filter按条件过滤,array_map对每个元素做转换array_keys/values提取键或值,in_array检查值sort/asort/ksort等 6 个排序函数覆盖大多数需求usort+<=>自定义排序,多维数组排序利器array_column从多维数组中提取特定列- 数组解构
[$a, $b] = $arr简洁赋值
📝 作业
- 给定两个用户标签数组,用
array_merge合并并用array_unique去重后输出。提示:array_unique()去重。 - 从一个成绩数组
[85, 92, 78, 95, 60]中:用array_filter过滤出及格(≥60)的分数,然后用array_map给每个分数加 5 分加分,最后排序输出。 - 创建一个至少包含 5 本书的多维数组(书名、作者、价格),用
usort按价格从低到高排序,再用array_column提取所有作者名。