PHP自定义排序核心是usort()等函数,需传入比较函数;推荐7.4+匿名函数,用太空船操作符安全比较,多字段需嵌套判断,注意null处理、locale及对象属性访问,性能敏感时可选array_multisort()。

usort() 里传匿名函数是最直接的写法
PHP 自定义排序核心就是 usort()(数组内排序)或 uasort()(保持键名)、uksort()(按键排序)。它们都要求第二个参数是「比较函数」:接收两个元素,返回负数、0 或正数,表示前者小于、等于或大于后者。
现代 PHP(7.4+)推荐用匿名函数,避免全局函数污染,也方便闭包捕获外部变量:
$users = [
['name' => 'Alice', 'score' => 85],
['name' => 'Bob', 'score' => 92],
['name' => 'Charlie', 'score' => 78]
];
usort($users, function($a, $b) {
return $a['score'] <=> $b['score']; // 升序
});
// 结果:Charlie, Alice, Bob
注意: 是太空船操作符,自动处理数字/字符串比较,比手写 if-else 返回 -1/0/1 更安全;别用 == 或 === 判断后返回布尔值——这会让排序逻辑失效。
多字段排序得嵌套判断,别用多个 usort()
想先按分数降序,分数相同时按姓名升序?不能对同一个数组调两次 usort(),后一次会完全打乱前一次的结果。
立即学习“PHP免费学习笔记(深入)”;
正确做法是在一个比较函数里分层判断:
usort($users, function($a, $b) {
// 先比 score(降序 → b 在前)
if ($a['score'] !== $b['score']) {
return $b['score'] <=> $a['score'];
}
// score 相同,再比 name(升序)
return $a['name'] <=> $b['name'];
});
- 用
!==判断是否「真正不同」,避免类型转换干扰(比如0 == '0'但排序时可能要区分) - 如果字段可能是 null 或缺失,先用
??提供默认值,否则NULL 'xxx'可能触发 notice - 字符串排序注意 locale:中文或带重音字符要用
collator_compare(),只做字节序比较
对象数组排序记得访问属性,别漏 $this
对对象数组排序时,别把 $a->name 写成 $a->getName() 除非你真有这个方法。更常见的是属性直接可读,或者用了魔术方法 __get()。
如果类用了 private/protected 属性,且没提供公共 getter,就得在比较函数里用反射(不推荐)或改用 array_map() 预处理成关联数组再排。
另一个坑:别在匿名函数里用 $this,除非你用 use ($this) ——但这是错的,$this 不能被闭包捕获。正确方式是把需要的数据提前抽出来,比如:
$sortBy = 'created_at';
usort($posts, function($a, $b) use ($sortBy) {
return $a->$sortBy <=> $b->$sortBy;
});
性能敏感场景慎用 usort(),考虑 array_multisort()
usort() 是原地排序,每次比较都调用 PHP 函数,当数组超 10 万行时,函数调用开销会明显拖慢速度。
如果排序依据是简单字段(比如全是数字或字符串),用 array_multisort() 配合 array_column() 更快:
$scores = array_column($users, 'score'); array_multisort($scores, SORT_DESC, $users);
它底层走 C 实现,不涉及用户态函数调用。缺点是不支持复杂逻辑(比如按「姓氏拼音首字母」排序),也难做多级条件分支。
真正卡顿的时候,先 var_dump(gettype($a['score'])) 确认数据类型是否一致——混合 int/string 会让 行为出人意料,这种隐式类型转换问题比排序逻辑本身更难排查。



















