ThinkPHP权重排序核心在于字段设计、排序语句构造与边界控制。使用top_weight整数字段控制置顶顺序,通过orderRaw显式拼接排序,避免覆盖。动态打分下推至SQL实时计算,前端传参需白名单校验,防止注入。
ThinkPHP 权重排序,最核心的思路其实就一句话:把“谁该排前面”的业务逻辑,落到数据库查询里,而不是靠 PHP 循环一通算。具体来说,无非是设计好字段、用对排序方法、管好前端传入的边界——下面展开聊聊几个关键点。

实现权重排序,重点不在写几个 order(),而在于字段设计、表达式构造、边界控制——否则很容易遇到卡顿、错序、维护困难的问题。下面直接上干货。
长期稳定更新的攒劲资源: >>>点此立即查看<<<
千万别用 is_top 这种布尔字段来应付置顶需求。布尔字段只能分两组,组内完全无序,运营一填就乱套。直接在文章表加一个 top_weight INT UNSIGNED DEFAULT 0 字段:
['number', 'between:0,999'],限制合理范围这样设计,运营人员只需要调整数值大小就能控制置顶顺序,简单又直观。
TP6 的 order() 是覆盖式,不是叠加式。如果模型作用域、基类控制器、中间件里都写了 order,最后只有最后一个生效,极易被覆盖。安全写法是统一收口:
public function scopeWithTopSort($query) { $query->orderRaw('top_weight DESC, create_time DESC'); }ArticleModel::scopeWithTopSort()->select()ORDER BY top_weight DESC, create_time DESC这样做的好处是:所有排序逻辑集中在一个地方,后续维护一目了然,也不会被其他地方的 order 意外覆盖。
比如按点击量 + 时间衰减综合排序,千万别建一个 weight 字段定时更新——数据一过期就失真,大表 UPDATE 还会锁库。正确做法是把计算逻辑下推到 SQL:
->field('*, (click * 0.7 + POW(UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(create_time), 0.3)) AS score'),再 ->orderRaw('score DESC')Db::execute("UPDATE article SET click = click + 1 WHERE id = "),绕过模型层,快且轻量这样动态算出来的分数,每次查询都是最新的,而且避免了定期更新字段带来的性能开销和一致性问题。
用户点表头切换 create_time desc,不能直接把 request 参数塞进 order(),否则字段名注入风险极高:
$allowed = ['create_time', 'score', 'view_count'];user.nickname)需显式 join,不能靠点号自动解析别小看这一步,很多线上问题都是因为前端传了不存在的字段名或者恶意构造的字段导致 SQL 报错甚至数据泄漏。白名单校验是安全底线。
侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述