一、函数定位与基本概念
sort()是PHP内置的数组排序函数,作用是把数组元素按升序重新排列。这个函数从PHP4.0开始提供,是数组排序操作中最基础的一个。
函数原型如下:
bool sort ( array &$array [, int $sort_flags = SORT_REGULAR ] );
参数说明:
| 参数 | 说明 | 是否必需 |
|---|---|---|
| array | 指定要排序的数组,以引用方式传入 | 必需 |
| sort_flags | 排序行为标志位,默认SORT_REGULAR | 可选 |
返回值方面,sort()成功时返回true,失败时返回false。它返回的是布尔值,不是排序后的数组。数组本身通过引用被直接修改,调用后原数组的顺序已经变化。
排序标志位的可选值:
| 标志位 | 含义 |
|---|---|
| SORT_REGULAR | 按常规方式比较元素,默认值 |
| SORT_NUMERIC | 按数值方式比较元素 |
| SORT_STRING | 按字符串方式比较元素 |
| SORT_LOCALE_STRING | 按当前区域设置比较字符串 |
| SORT_NATURAL | 按自然顺序比较字符串 |
| SORT_FLAG_CASE | 可与SORT_STRING或SORT_NATURAL组合,忽略大小写 |
这里有一个关键机制需要先明确:sort()会为数组元素分配新的键。无论传入的是索引数组还是关联数组,排序之后所有键名都会被重建为从0开始的数字键。关联数组的字符串键会全部丢失,值和键的对应关系被切断。这个特性是sort()和asort()的核心区别,也是实际项目中最容易踩坑的地方。
二、基础用法与代码号学习编程示例
先看一个字符串数组的排序例子。代码号学习编程时,常用乐器名称数组来演示升序排列:
<?php
$guitars = array("classical", "acoustic", "electric");
sort($guitars);
print_r($guitars);
?>
输出结果为:
Array
(
[0] => acoustic
[1] => classical
[2] => electric
)
sort()按字母顺序把三个元素重新排列。默认的SORT_REGULAR标志位对字符串来说,比较逻辑接近字典序。
再看一个汽车品牌数组:
<?php
$cars = array("bmw", "audi", "nissan");
sort($cars);
print_r($cars);
?>
输出结果为:
Array
(
[0] => audi
[1] => bmw
[2] => nissan
)
audi排在bmw前面,nissan排在之后,符合字母升序。
再看一个课程名称数组:
<?php
$subject = array("os", "compiler", "dbms", "networking");
sort($subject);
print_r($subject);
?>
输出结果为:
Array
(
[0] => compiler
[1] => dbms
[2] => networking
[3] => os
)
这三个例子说明,sort()对字符串数组的排序结果符合字母表顺序。注意os排在之后,因为o的字母序在n之后。
三、数值排序与rsort()对比
第三个例子展示了rsort()和sort()的配合使用,也暴露了数值排序中需要注意的地方:
<?php
$numbers = array(50, 100, 20, 1, 400);
rsort($numbers);
print_r($numbers);
sort($numbers);
print_r($numbers);
?>
输出结果为:
Array
(
[0] => 400
[1] => 100
[2] => 50
[3] => 20
[4] => 1
)
Array
(
[0] => 1
[1] => 20
[2] => 50
[3] => 100
[4] => 400
)
rsort()是sort()的降序版本,把数组从大到小排列。sort()再把它从小到大排列。两次操作都直接修改了原数组。
这里有一个项目实战中的踩坑经历。曾经处理价格数据时,价格从数据库取出时是字符串类型,比如"100"、"50"、"20"。直接调用sort()后,结果变成了"100"、"20"、"50",因为默认的SORT_REGULAR在比较字符串数字时,按字符串规则处理,"100"的首字符1小于"20"的首字符2,所以"100"排在了前面。
解决方法是显式指定SORT_NUMERIC:
<?php
$prices = array("100", "50", "20");
sort($prices, SORT_NUMERIC);
print_r($prices);
?>
输出结果为:
Array
(
[0] => 20
[1] => 50
[2] => 100
)
这个经历说明,当数组中元素的类型不确定,或者元素是字符串形式的数字时,指定SORT_NUMERIC可以避免按字符串规则排序带来的偏差。
四、排序标志位的选择策略
排序标志位决定了sort()内部如何比较元素。选错标志位会导致排序结果偏离预期。
SORT_REGULAR:默认值,按PHP的常规比较规则处理。对数字和字符串混合的数组,比较规则比较复杂。PHP8之前,字符串和数字比较时行为有过多次调整。如果数组类型统一,SORT_REGULAR通常够用。如果类型混杂,建议显式指定标志位。
SORT_NUMERIC:按数值比较。适合元素是数字或数字字符串的场景。价格、数量、评分、年龄等数据排序时使用。
SORT_STRING:按字符串比较。适合元素是文本的场景。注意字符串比较是逐字节进行的,大写字母和小写字母的排序位置不同。
SORT_LOCALE_STRING:按当前区域设置比较字符串。适合需要处理多语言排序的场景,比如中文拼音排序、欧洲语言的特殊字符排序。使用前需要确认服务器安装了对应的locale。
SORT_NATURAL:自然顺序排序。适合包含数字的字符串,比如"img1"、"img2"、"img10"。默认的SORT_STRING会把"img10"排在"img2"前面,因为逐字符比较时1小于2。SORT_NATURAL会按人类直觉把"img2"排在"img10"前面。
<?php
$files = array("img10", "img2", "img1");
sort($files, SORT_NATURAL);
print_r($files);
?>
输出结果为:
Array
(
[0] => img1
[1] => img2
[2] => img10
)
SORT_FLAG_CASE:这个标志位不能单独使用,需要和SORT_STRING或SORT_NATURAL组合,实现忽略大小写的排序。
<?php
$words = array("Banana", "apple", "Cherry");
sort($words, SORT_STRING | SORT_FLAG_CASE);
print_r($words);
?>
输出结果为:
Array
(
[0] => apple
[1] => Banana
[2] => Cherry
)
个人建议:在业务代码中,只要数组元素的类型是明确的,就显式指定排序标志位。这样代码意图更清楚,也不受PHP版本间比较规则变化的影响。
五、关联数组键名丢失问题
这是sort()最需要警惕的地方。看下面这个例子:
<?php
$score = array("张三" => 85, "李四" => 92, "王五" => 78);
sort($score);
print_r($score);
?>
输出结果类似:
Array
(
[0] => 78
[1] => 85
[2] => 92
)
原本的键名"张三"、"李四"、"王五"全部消失,变成了0、1、2。值和姓名的对应关系被彻底切断。排序后的数组只知道分数,不知道谁得了多少分。
项目实战中有一次做成绩排名功能,学生姓名和分数用关联数组存储,键名是姓名,值是分数。为了按分数排序,直接对数组调用了sort()。结果分数排序了,但姓名丢失了,排名结果无法对应到学生。后来改用asort()才解决了问题。
asort()按值排序但保留键名,适合关联数组:
<?php
$score = array("张三" => 85, "李四" => 92, "王五" => 78);
asort($score);
print_r($score);
?>
输出结果为:
Array
(
[王五] => 78
[张三] => 85
[李四] => 92
)
键名和值的对应关系保持完好,分数按升序排列,姓名跟随分数一起移动。
这个踩坑经历说明:如果数组的键名承载业务含义,比如姓名、ID、标识符,直接使用sort()会破坏这种关系。正确的做法是根据需求选择asort()(按值排序保留键名)、ksort()(按键名排序)或arsort()(按值降序保留键名)。
六、sort()家族与相关函数对比
sort()和几个函数容易混淆,需要分清使用场景。
sort()与rsort():sort()升序,rsort()降序。两者都重建键名,都修改原数组。
sort()与asort():sort()按值升序但重建键名,asort()按值升序但保留键名。关联数组排序用asort()。
sort()与ksort():sort()按值排序,ksort()按键名排序。需要按键名顺序整理数组时用ksort()。
sort()与usort():sort()使用内置比较规则,usort()使用用户自定义比较函数。需要按复杂规则排序时用usort()。
sort()与array_multisort():sort()对单个数组排序,array_multisort()可以对多个数组同时排序,或者对多维数组按指定列排序。处理表格数据、多列排序时用array_multisort()。
个人见解:sort()的定位是“对值排序,不关心键名”的场景。如果键名重要,就应该换用asort()或ksort()。选择排序函数时,先问两个问题:按值还是按键?键名要不要保留?这两个问题的答案就能确定用哪个函数。
七、本节课程知识要点
-
sort()用于对数组元素按升序排列,原数组以引用方式被直接修改。
-
函数返回布尔值,成功为true,失败为false,不返回排序后的数组。
-
无论传入索引数组还是关联数组,排序后键名都会重建为从0开始的数字键。
-
关联数组的字符串键在sort()后会丢失,键值对应关系被切断。
-
键名有业务含义时,应使用asort()按值排序保留键名,或ksort()按键名排序。
-
SORT_REGULAR是默认标志位,类型混杂时建议显式指定SORT_NUMERIC或SORT_STRING。
-
SORT_NATURAL适合包含数字的字符串,SORT_FLAG_CASE需要与其他标志位组合使用。
-
字符串形式的数字排序时,不指定SORT_NUMERIC会按字符串规则处理,结果可能偏离预期。
-
需要按键名排序用ksort(),需要自定义规则用usort(),需要多数组联动排序用array_multisort()。
sort()的用法本身不复杂,核心在于理解它的引用修改和键名重建两个特性,以及排序标志位对比较规则的影响。把这两个点弄清楚,再根据业务需求选择保留键名还是重建键名,数组排序就不会出问题。