Laravel 使用 事件和监听器实现 数据状态变更

首先知道事件是什么

1.事件的概念

事件(Event)是 Laravel 中实现观察者模式 的一种机制,它允许应用程序中的不同部分进行松耦合的通信。

通俗一点就是,发生在应用程序中的动作或者事情。例如:

  1. 用户注册成功后,需要发邮件,发短信,初始化数据;
  2. 订单支付成功后,库存处理,消息发送,订单处理;
  3. 文章发布成功后,用户的积分,通知审核者,推送阅读者;
  4. 。。。。

类似以上这些动作或事情,都可以看着一个个单独的事件。

2.事件组成部分

  1. 事件类(Event):承载事件相关数据的对象

  2. 事件触发:在代码中明确触发事件的位置

  3. 监听器(Listener):响应事件并执行处理的类

3.怎么工作

触发事件 -> 创建事件对象 -> 事件分发器 -> 匹配监听器 -> 执行监听器逻辑

4.事件特点

  1. 解耦性:将某些动作和主体功能的逻辑拆分,例如将用户注册和发邮件拆分开,用户注册后,直接触发邮件事件。根本不需要知道怎么发邮件的。两个互不影响。
  2. 可扩展性:一个事件支持多个监听器,例如用户注册成功后,原有一个监听器去发邮件,如果现在有个发短信的需求,直接添加一个新的监听器即可,不需要去修改原有的代码。减少出错率
  3. 队列支持:监听器可以同步执行,也可以异步执行。例如发邮件,处理大量的耗时任务,可以直接在异步里面执行,不影响主体功能

数据状态变更 事件开发

1.创建事件

使用 Artisan 命令创建一个新事件:

php 复制代码
php artisan make:event MyCustomState

app/Events 目录下会自动生成一个事件类。编辑一下

php 复制代码
<?php

namespace App\Events;

use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class MyCustomState
{
    use Dispatchable, SerializesModels;

    public $data;

    /**
     * 创建一个新的事件实例
     *
     * @param mixed $data 需要传递的数据
     * @return void
     */
    public function __construct($data)
    {
        $this->data = $data;
    }
}

__construct里面进行赋值处理 $this->data = $data;

2.创建监听器

使用命令行创建监听器

php 复制代码
 php artisan make:listener ProcessMyCustomState --event=MyCustomState

编辑监听器文件 app/Listeners/ProcessMyCustomState .php:

注意,处理这个事件的逻辑就在监听器里面实现。例如发短信,发邮件,等等

php 复制代码
<?php

namespace App\Listeners;

use App\Events\MyCustomState;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;

class ProcessMyCustomState 
{
    /**
     * 处理事件
     *
     * @param MyCustomEvent $event
     * @return void
     */
    public function handle(MyCustomState $event)
    {
       //接收事件的数据
        $data = $event->data;
        
        // 例如:记录日志、发送邮件、处理数据等
        \Log::info('事件已处理,数据:', ['data' => $data]);
        
        // 自我表现的时候到了,开始肆无忌惮的搭建屎山工程
        // ........
    }
}

3.注册事件和监听器

目前事件和监听器是两个独立的类,接下来要让监听器监听事件。也就是所谓的注册对应关系

编辑 app/Providers/EventServiceProvider.php 添加以下代码

php 复制代码
protected $listen = [
    MyCustomState::class => [
        ProcessMyCustomState::class,
    ],
];

请注意

MyCustomState::class 对应的是一个数组,也就是里面可以有多个监听器,即多个监听器监听一个事件

例如发短信,发邮件,等等。每个独立实现可以为一个监听器

这样就建立关系了。接下来只需要去触发这个事件即可

4.在控制器中触发事件

编辑一个控制器文件

php 复制代码
<?php

namespace App\Http\Controllers;

use App\Events\MyCustomEvent;
use Illuminate\Http\Request;

class MyController extends Controller
{
    public function triggerEvent(Request $request)
    {
        // 一些业务逻辑...
        $eventData = [
            'user_id' => auth()->id(),
            'action' => 'custom_action',
            'timestamp' => now(),
        ];
        
        // 触发事件
        event(new MyCustomState($eventData));
        
        // 或者也可以使用辅助函数
        // MyCustomState::dispatch($eventData);
        
        return response()->json(['message' => '事件已触发']);
    }
}

可以用 event(new MyCustomState($eventData)); 或者 MyCustomState::dispatch($eventData); 触发事件

以上就是正常一个事件的开发流程了。

如果监听器的逻辑较为复杂或者非常耗时,那么建议这个监听器进行异步执行。可以让监听器实现 ShouldQueue 接口

5.监听器队列处理(视情况而定)

简单说一下,什么情况使用队列监听器

  1. 耗时操作:发送邮件、生成报表、处理图片等

  2. 第三方API调用:支付网关、短信服务等

  3. 非关键操作:日志记录、数据分析等不需要即时完成的操作

  4. 高流量场景:需要快速响应用户而不等待后台处理完成

监听器实现 ShouldQueue 接口
php 复制代码
use Illuminate\Contracts\Queue\ShouldQueue;

class ProcessMyCustomState implements ShouldQueue
{
    use InteractsWithQueue;
    
    // 指定队列连接
    public $connection = 'ProcessMyCustomStateQueue';
    
    // 指定队列名称
    public $queue = 'emails';
    
    // 延迟处理(秒)
    public $delay = 60;
    
    // 最大尝试次数
    public $tries = 3;
    
    // 超时时间(秒)
    public $timeout = 30;
    
    public function handle(MyCustomEvent $event)
    {
       // 处理事件逻辑
        $data = $event->data;
        
        // 例如:记录日志、发送邮件、处理数据等
        \Log::info('事件已处理,数据:', ['data' => $data]);
        
        // 此处就是异步处理的逻辑
        // .....
    }
}
运行队列进程

如果使用队列,那么就必须运行队列的进程,这样才能及时处理到监听器的逻辑。

如果对队列不熟悉的同学,我后面会写一篇关于队列的文章,让大家学习一下

命令行启动队列

php 复制代码
php artisan queue:work  --queue=ProcessMyCustomStateQueue

启动后,当事件触发时,命令行会显示进程处理日志

总结

这就是在 Laravel 中实现事件和监听器的完整流程。

这种模式有助于解耦代码,使得业务逻辑更加清晰,也便于后期维护和扩展。

你可以根据需要创建多个监听器来监听同一个事件,或者为事件添加更多的属性和方法。

相关推荐
BingoGo8 小时前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php
JaguarJack8 小时前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php·服务端
BingoGo1 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php
JaguarJack1 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php·服务端
JaguarJack2 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
后端·php·服务端
BingoGo2 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
php
BingoGo3 天前
告别 Laravel 缓慢的 Blade!Livewire Blaze 来了,为你的 Laravel 性能提速
后端·laravel
JaguarJack3 天前
告别 Laravel 缓慢的 Blade!Livewire Blaze 来了,为你的 Laravel 性能提速
后端·php·laravel
郑州光合科技余经理4 天前
代码展示:PHP搭建海外版外卖系统源码解析
java·开发语言·前端·后端·系统架构·uni-app·php
QQ5110082854 天前
python+springboot+django/flask的校园资料分享系统
spring boot·python·django·flask·node.js·php