跳转到主内容
趣航编程网 - 趣学编程,启航技术之路!

ThinkPHP模型怎么使用查询事件_ThinkPHPbefore_select监听指南【指南】

TP6已移除before_select事件,因其重构了查询机制,改用Query层的BeforeExecute事件和模型scope替代;TP5.1/5.2中该事件仅支持日志等旁路操作,无法修改查询条件。 ThinkPHP 的
before_select
事件在 6.x 版本中已被移除,5.1/5.2 仍支持但行为受限——它不接收查询条件参数,无法动态修改
where
field
,仅适合做日志记录或简单拦截。 为什么
before_select
在 TP6 中用不了 TP6 彻底重构了查询构建器与模型生命周期,取消了所有以
before_*
/
after_*
命名的模型事件。取而代之的是更统一、可组合的「查询作用域(scope)」和「事件监听器(Event Listener)」机制。
before_select
在 TP5.1/5.2 中触发时机早于 SQL 编译,但传入的参数只有
$model
实例,没有
$query
对象,无法干预实际查询逻辑 TP6 中模型不再直接暴露查询过程,
select()
等方法底层调用的是
Query
类,事件钩子已下沉到
think\db\Query
层,对应的是
BeforeExecute
AfterExecute
全局事件 试图在 TP6 模型中定义
before_select
方法不会报错,但完全不会被调用 TP5.1/5.2 中
before_select
的真实能力边界 它只能用于「只读旁路操作」,比如统计调用次数、写日志、抛异常中断,但不能改查询条件。 以下写法看似有效,实则无效:
$query->where('status', 1)
—— 因为
$query
参数根本不存在,
before_select
只接收
$model
正确用法示例(仅日志):
protected static function beforeSelect($model) { \think\Log::info('Model ' . get_class($model) . ' select triggered'); }
若需统一加条件,请改用
scope
public function scopeActive($query) { return $query->where('status', 1); } // 调用:UserModel::active()->select();
TP6 替代方案:用
BeforeExecute
事件拦截原生查询 如果真需要在 SQL 执行前统一处理(如多租户字段注入、敏感字段过滤),必须监听数据库查询级别的事件,而非模型事件。 PHP 8.5.5 PHP 8.5.5 是 PHP 8.5 分支的维护更新版本。该版本延续了“小步快跑”的迭代逻辑,通过深度错误修复、底层性能微调以及安全加固,旨在为开发者提供一个更健壮、更高效的运行环境。该版本严格遵守语义化版本规范,不包含破坏性变更。 下载 立即学习 “ PHP免费学习笔记(深入) ”; 在
app/event.php
中注册:
return [ 'think\db\Query' => [ 'BeforeExecute' => [\app\listener\QueryBeforeExecute::class, 'handle'], ], ];
QueryBeforeExecute::handle()
接收
$query
对象,可调用
$query->getOptions()
查看当前条件,用
$query->options(['where' => [...]])
修改(注意:部分选项不可直接覆盖,需谨慎) 该事件影响所有查询(包括原生
Db::table()
),不是模型专属,务必加判断:
if ($query->getTable() === 'user') { ... }
性能敏感场景慎用——每次查询都触发,且修改
options
可能破坏缓存一致性 真正要统一控制查询逻辑,别依赖已废弃的模型事件;TP5 就老实用
scope
,TP6 就走
Query
事件 + 表名判断。最常被忽略的一点:TP6 的模型
select()
方法本身是静态代理,背后根本没有「模型级 select 钩子」这回事。

相关文章