usort配合匿名函数是PHP排序多维数组最常用方式,需注意字段存在性、类型统一、大小写及多字段逐级比较;array_multisort适用于大数据量但会重置键名;对象数组须用->访问或getter方法。

用 usort 配合匿名函数排序多维数组
PHP 原生不支持直接按子数组字段排序,usort 是最常用且可控的方式。它不依赖键名,只看数组值,适合索引数组或结构一致的关联数组。
常见错误是传入错误的比较逻辑,比如用 == 或忘记处理 null/string 类型导致排序错乱;或者误用 sort(只排值,不保留键值关系)。
- 比较函数必须返回整数:
-1(小在前)、0(相等)、1(大在前) - 字段不存在时,建议用
??提供默认值,避免Notice - 字符串字段排序注意大小写:
strcasecmp比strcmp更稳妥
$data = [
['name' => 'Alice', 'score' => 85],
['name' => 'bob', 'score' => 92],
];
usort($data, function($a, $b) {
return $b['score'] <=> $a['score']; // 降序
});
按多个字段排序:嵌套 usort 还是单次比较?
嵌套 usort(先按 A 排,再按 B 排)会覆盖前一次结果,不可取。正确做法是在一个比较函数里逐级判断。
典型场景是「优先按状态,状态相同时按更新时间倒序」。这里容易踩的坑是没用三元运算符或提前 return,导致后续字段没生效。
立即学习“PHP免费学习笔记(深入)”;
- 用飞船操作符
处理数字/日期,用strcasecmp处理字符串 - 字段类型不一致(如时间存为字符串)会导致排序异常,建议统一转为
strtotime后比较 - PHP 7.4+ 可用箭头函数简化,但调试时不如普通匿名函数直观
usort($items, function($a, $b) {
$statusDiff = $a['status'] <=> $b['status'];
if ($statusDiff !== 0) return $statusDiff;
return strtotime($b['updated_at']) <=> strtotime($a['updated_at']);
});
array_multisort 的适用边界和陷阱
array_multisort 看起来强大,但它要求你先把目标字段抽成独立数组,且对键名敏感——关联键会被重置为数字索引,原始键丢失。
它适合已知字段存在、数据量大且不依赖原键的场景;但一旦子数组结构不一致(比如某些缺 price),就会报 Warning: array_multisort(): Array sizes are inconsistent。
- 必须用
array_column($arr, 'field')提取列,不能直接传子数组 - 升序用
SORT_ASC,降序用SORT_DESC,别漏掉第二个参数 - 如果原数组是关联数组,排序后键会变,需用
array_values强制重索引(或接受键被重排)
$prices = array_column($products, 'price'); array_multisort($prices, SORT_DESC, $products);
对象数组 vs 关联数组:排序逻辑要不要改?
如果数组元素是对象(如 new User()),usort 内部访问方式要改成 $a->name 或 $a->getName(),不能用 $a['name']。否则直接报 Fatal error: Cannot use object of type X as array。
更隐蔽的问题是对象属性可能被设为 private,此时必须走 getter 方法,硬访问会静默失败(返回 null)导致排序全乱。
- 统一用 getter 能避免权限问题,也方便后期加逻辑(如格式化)
- 如果对象实现了
__get,确保它不抛异常或返回默认值 - 不确定结构时,先
var_dump(gettype($a))确认是 array 还是 object
复杂点往往不在语法,而在你没意识到:某个字段在部分数据里根本不存在,或者类型混着来(字符串 "100" 和整数 100 并存)。这种时候,光靠排序函数没用,得先 normalize 数据结构。



















