usort排序必须严格按规则编写比较函数,仅接受整数返回值(负数、0、正数),返回布尔值、浮点数、null或无返回将导致排序错误;需处理字段缺失、类型不一致、多条件优先级及键名丢失等问题。

usort 不是“怎么用”,而是“必须按规则写比较函数,否则排序错得离谱”。它不关心你传的是数字、字符串还是对象,只认回调函数返回的整数:负数($a 在 $b 前)、正数($a 在 $b 后)、0(相等)。返回布尔值、浮点数、null 或没返回,都会导致不可预测结果。
比较函数必须返回整数,不能返回布尔值
常见错误是写成 return $a['age'] > $b['age']; —— 这返回 true/false(即 1/0),usort 无法区分“小于”关系,排序会塌陷成半有序或完全乱序。
- 数字字段升序:用减法
return $a['age'] - $b['age']; - 字符串字段升序:用
strcmp($a['name'], $b['name']),不是==或> - PHP 7+ 可用太空船操作符简化:
return $a['score'] $b['score'];,但注意它对null和类型混合仍可能出错 - 绝对不要在比较函数里做
echo、die或修改外部变量——usort内部调用顺序不可控,副作用难调试
二维数组按某字段排序时,字段可能不存在或为 null
直接访问 $a['status'] 而不判断,会触发 Notice: Undefined index;若字段是 null 或空字符串,减法或 strcmp 会给出错误偏序(比如 null - 5 === -5,把 null 排到最前,而非末尾)。
- 安全写法:先检查键是否存在,再归一化值,例如
$valA = $a['status'] ?? 'z';(用字典末尾字符占位) - 更健壮的做法是统一映射缺失值为极大整数:
$posA = array_key_exists('status', $a) ? array_search($a['status'], $validStatuses) : PHP_INT_MAX; - 避免用
isset($a['field']) === false后直接return 1——这会让所有缺失项互相视为“相等”,顺序随机
多条件排序要逐层 return,别嵌套 if-else
比如先按 city 升序,相同再按 age 降序。错误写法是写一个大 if 块套两层逻辑,容易漏 return;正确做法是“能定胜负就立刻退出”。
usort($users, function($a, $b) {
$cityCmp = strcmp($a['city'] ?? '', $b['city'] ?? '');
if ($cityCmp !== 0) {
return $cityCmp;
}
// city 相同,按 age 降序
return $b['age'] - $a['age'];
});
- 每层比较后都用
if (...) return ...;,别靠 else 续命 - 字段类型不一致时(如
$a['age']是字符串"25"),先(int)强转,否则减法会静默转为 0 - PHP 8.5.5 对类型混合比较更严格,未转类型的字符串数字参与减法会触发
Warning
排序后原键名丢失,且相等元素顺序不保证
usort 永远重置键名为连续数字索引(0, 1, 2...),不会保留 ['id_123' => [...]] 这类关联键。另外,当比较函数返回 0,PHP 不保证它们相对位置不变——尤其在 PHP 4.1.0+ 后,算法改用 Introsort,相同项可能被重排。
- 需要保留原始键?改用
uasort,它维持键名关联 - 依赖“相等项顺序稳定”?别依赖——要么在比较函数里加入唯一次级键(如原始索引),要么排序前加一层预处理标记
- 性能敏感场景(数组超 10k 元素),避免在比较函数里反复调用
array_search或strlen;可先预建映射表$orderMap = array_flip($referenceArray);,查 O(1)
真正麻烦的从来不是语法,而是比较函数里那几行逻辑——它既不能抛异常,又不能跳过,还必须每次返回确定整数。写完务必用含 null、空字符串、类型混杂、重复值的测试数据跑一遍,否则上线后排序“看起来差不多”,实则关键项错位。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











