ThinkPHP自定义排序分数据库查询排序和PHP数组重排两种:前者用白名单字段+方向校验+数组传参order()确保安全;后者用usort()按业务逻辑自定义比较函数实现。

ThinkPHP 里说的“自定义排序规则”,其实分两种场景:一种是查数据库时按你选的字段和方向排(比如用户点表头想按价格降序),另一种是查完数据后对 PHP 数组做特殊逻辑重排(比如按中文姓氏笔画、按状态优先级)。零基础不用怕,掌握下面两招就够用。
数据库查询时动态选字段+方向(安全写法)
这不是让你随便输什么字段都行,而是提前圈定几个“可信字段”,再让用户从中选一个怎么排。核心就三点:白名单、方向校验、数组传参。
- 先列好允许排序的字段,比如
['id', 'price', 'create_time', 'sort'] - 从请求里取字段名和方向,但必须检查是否在白名单里,方向只能是
asc或desc - 用数组方式调
order(),例如->order([$field => $dir]),TP 会自动加反引号防注入
示例代码:
(直接复制到控制器方法里就能跑)$allowFields = ['id', 'price', 'create_time'];<br>$field = input('sort_field', 'id');<br>$dir = in_array(input('sort_dir'), ['asc', 'desc']) ? input('sort_dir') : 'asc';<br>if (!in_array($field, $allowFields)) { $field = 'id'; }<br>$list = Db::name('goods')->order([$field => $dir])->select();
立即学习“PHP免费学习笔记(深入)”;
PHP 数组里按业务逻辑重排(usort 实战)
查出来的数据已经是数组了,但你想让它按“未完成 > 进行中 > 已完成”这种状态顺序排,或者按名字拼音、按金额区间分段,就得用usort()。
- 写一个比较函数,接收两个元素
$a和$b - 函数里只做一件事:返回负数(
$a该在前)、正数($b该在前)、0(相等) - 数字比大小用减法,字符串比大小用
strcmp(),多条件就逐级判断
比如按自定义状态排序:
usort($data, function($a, $b) {<br> $order = ['draft' => 0, 'pending' => 1, 'done' => 2];<br> return ($order[$a['status']] ?? 99) - ($order[$b['status']] ?? 99);<br>});
别踩的坑:这些写法看着快,实际危险或无效
新手常抄网上老教程,结果埋雷:
-
别拼字符串:
order('price ' . input('dir'))——用户输desc, (SELECT ...)就直接执行 -
别信 Db::raw():
order(Db::raw(input('field') . ' ' . input('dir')))——等于把 SQL 闸门全打开 -
别漏分页透传:用了
paginate(),记得加->appends(['sort_field' => ..., 'sort_dir' => ...]),否则翻页后排序丢了 -
别混淆 usort 和 uasort:如果数组键名有意义(比如 ID 作键),要用
uasort()保留键名



















