sort($array) 原地把数组按升序排序。它会修改你传入的变量并返回 true,所以要把它单独写成一行,然后再使用这个数组。rsort() 按降序排序。
对于“按值还是按键”“升序还是降序”“保留键还是不保留”的每一种组合,PHP 都有对应的排序函数:
| 函数 | 排序依据 | 顺序 | 键 |
|---|---|---|---|
sort | 值 | 升序 | 重新编号为 0, 1, 2 |
rsort | 值 | 降序 | 重新编号 |
asort | 值 | 升序 | 保留 |
arsort | 值 | 降序 | 保留 |
ksort | 键 | 升序 | 保留 |
krsort | 键 | 降序 | 保留 |
usort | 你的函数 | 由你决定 | 重新编号 |
uasort | 你的函数 | 由你决定 | 保留 |
uksort | 你作用于键的函数 | 由你决定 | 保留 |
按值给关联数组排序
对关联数组调用 sort() 会丢掉键。用 asort() 按值排序,并让每个键和它的值保持对应;用 arsort() 则把最大的排在最前面。
用 ksort 按键给数组排序
ksort() 按键排序,krsort() 按键倒序排序。在输出设置项或以固定顺序构建查询字符串之前,这很方便。
用 usort 和太空船运算符自定义顺序
usort($array, $callback) 让你决定顺序。回调函数接收两个元素:如果第一个应该排在前面,就返回负数;如果第二个应该排在前面,就返回正数;如果两者相等,就返回 0。太空船运算符 <=> 返回的正是这样的值。
banana 和 cherry 长度相同,所以回调对它们返回 0,它们保持原来的顺序。从 PHP 8.0 开始,PHP 的排序是稳定的:相等的元素保持之前的顺序。
按某个值给多维数组排序
要按某个字段给一组行排序,就在 usort 中比较这个字段。要按两个字段排序,就比较数组:<=> 会逐个元素比较,所以只有第一个字段相等时,第二个字段才起作用。
第二个比较把 $b["age"] 放在左边、$a["age"] 放在右边,这样只反转了年龄的顺序。array_multisort(array_column($people, 'city'), SORT_ASC, array_column($people, 'age'), SORT_DESC, $people) 不用回调也能得到相同的顺序:它按提取出来的列排序,并相应地重新排列 $people。
自然排序和排序标志
默认情况下,PHP 把数字当作数字比较,把字符串当作字符串比较。带数字的文件名排出来的顺序会出人意料:img10 排在 img2 前面,所有大写开头的名字都排在小写开头的名字前面。排序标志可以改变值的比较方式。
SORT_NATURAL 把连续的数字当作数字来读,SORT_FLAG_CASE 忽略大小写,SORT_STRING 即使对数字字符串也强制逐字符比较。natsort() 和 natcasesort() 是同样的思路,但会保留键。
常见错误:把 sort 的结果赋值给变量
所有排序函数都返回 true,并修改你传入的数组。把返回值赋给变量会丢掉数组:
如果需要一个排好序的副本,同时保留原数组,就先把数组复制到一个新变量中,再对副本排序,就像上面 asort 示例中对 $copy 所做的那样。
常见问题
为什么 sort() 返回的是 true,而不是排好序的数组?
PHP 的排序函数通过引用原地排序数组,并返回 true。把 sort($arr); 单独写成一行,之后再使用 $arr。写成 $arr = sort($arr); 会用 true 替换掉你的数组。
怎么按值给关联数组排序并保留键?
升序用 asort($arr),降序用 arsort($arr)。sort() 和 rsort() 也按值排序,但会丢掉键,从 0 开始重新编号。
PHP 中怎么按某个值给多维数组排序?
用 usort 配合太空船运算符比较这个字段:usort($rows, fn($a, $b) => $a['age'] <=> $b['age']);。交换 $a 和 $b 就是降序;要按两个字段排序,就比较数组,比如 [$a['city'], $a['age']] <=> [$b['city'], $b['age']]。
PHP 的排序是稳定的吗?
是的,从 PHP 8.0 开始,所有排序函数都是稳定的:比较结果相等的元素保持排序前的顺序。正因如此,先按一个字段排序再按另一个字段排序,才能得到预期的结果。
怎么按自然顺序给带数字的字符串排序?
使用 natsort($arr) 或 sort($arr, SORT_NATURAL),它们会把 img2 排在 img10 前面。加上 SORT_FLAG_CASE(SORT_NATURAL | SORT_FLAG_CASE)或使用 natcasesort 可以忽略大小写。