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 层嵌套就该考虑是否应该用对象或类来组织数据了。数组适合简单结构,复杂结构用对象更清晰。

📖 小节

📝 作业

  1. 给定两个用户标签数组,用 array_merge 合并并用 array_unique 去重后输出。提示:array_unique() 去重。
  2. 从一个成绩数组 [85, 92, 78, 95, 60] 中:用 array_filter 过滤出及格(≥60)的分数,然后用 array_map 给每个分数加 5 分加分,最后排序输出。
  3. 创建一个至少包含 5 本书的多维数组(书名、作者、价格),用 usort 按价格从低到高排序,再用 array_column 提取所有作者名。
Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏