laravel事件机制通过自定义事件、监听器、模型钩子、查询构建器宏及数据库监听实现解耦与生命周期控制:一、用php artisan make:event生成事件类并触发;二、用make:listener创建监听器并在eventserviceprovider注册;三、在模型boot中使用creating/created等钩子;四、用builder::macro扩展查询构建器;五、用db::listen捕获sql执行信息。

在Laravel框架中,事件机制用于解耦应用逻辑,使代码更易维护;查询生命周期技巧则涉及模型查询构建、执行及结果处理各阶段的干预方式。以下是具体使用方法:
一、定义与触发自定义事件
Laravel事件基于观察者模式,需先定义事件类与监听器,再通过Event::dispatch()或事件助手函数触发。事件对象可携带任意数据,供监听器接收处理。
1、运行命令生成事件类:php artisan make:event UserRegistered。
2、在生成的UserRegistered.php文件中,于构造函数内声明并赋值属性,如$this->user = $user。
3、在需要触发的位置调用:event(new UserRegistered($user)) 或 Event::dispatch(new UserRegistered($user))。
二、注册事件监听器并处理逻辑
监听器负责响应特定事件,可同步或异步执行。注册方式包括自动发现、手动注册于EventServiceProvider,或动态绑定。
1、运行命令生成监听器:php artisan make:listener SendWelcomeEmail --event=UserRegistered。
2、在handle方法中编写业务逻辑,例如发送邮件:$event->user->email 可直接访问事件携带的数据。
3、在EventServiceProvider的$listen数组中添加映射:'App\Events\UserRegistered' => ['App\Listeners\SendWelcomeEmail']。
三、使用模型事件钩子拦截查询生命周期
Eloquent模型提供静态事件钩子(如creating、created、updating、updated等),在模型实例状态变更时自动触发,适用于审计、默认值填充、权限校验等场景。
1、在模型类中使用静态boot方法注册钩子:static::creating(function ($model) { $model->uuid = Str::uuid(); });。
2、多个钩子可链式注册:static::saved(function ($model) { Log::info('Model saved', ['id' => $model->id]); });。
3、钩子内可抛出异常中断保存流程:if (empty($model->name)) { throw new ValidationException(); }。
四、利用查询构建器宏扩展生命周期控制点
通过Query Builder的macro方法注入自定义方法,在where、get、paginate等调用前后插入逻辑,实现细粒度生命周期干预。
1、在ServiceProvider的boot方法中定义宏:Builder::macro('withTrashedIfAdmin', function () { return $this->when(auth()->user()?->is_admin, function ($query) { return $query->withTrashed(); }); });。
2、在查询中调用该宏:User::query()->withTrashedIfAdmin()->get()。
3、宏内可访问当前查询实例并修改其行为,例如动态添加select字段或约束条件。
五、监听数据库查询事件获取原始SQL执行信息
DatabaseManager提供connection().listening()方法,可在每次SQL语句执行前捕获其原始SQL、绑定参数及执行时间,适用于性能分析与日志记录。
1、在服务提供者的boot方法中注册监听器:DB::listen(function ($query) { Log::debug($query->sql, $query->bindings); });。
2、$query对象包含sql、bindings、time(毫秒)、connectionName四个属性,均可直接读取。
3、可通过判断$query->time > 500筛选慢查询:if ($query->time > 500) { Slack::send("Slow query: {$query->sql}"); }。











