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 中实现事件和监听器的完整流程。

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

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

相关推荐
Dy大叔5 小时前
ThinkPHP 5 根据账户类型的不同统计数据中使用CASE WHEN THEN SQL语句实例
mysql·php
alden_ygq8 小时前
/etc/kdump.conf 配置详解
服务器·网络·php
Hzhile10 小时前
攻防世界-php伪协议和文件包含
android·开发语言·安全·web安全·网络安全·php
s_little_monster16 小时前
【Linux】网络基础
linux·运维·网络·笔记·学习·php·学习方法
alden_ygq17 小时前
K8S node ARP 表爆满 如何优化
容器·kubernetes·php
cnn-jxx2 天前
基于PHP实现的easy管理系统
php
keenx2 天前
centos7.0无法安装php8.2/8.3
centos·php
toooooop83 天前
openssl_error_string() 不要依赖错误信息作为逻辑判断
php·openssl
firshman_start3 天前
第六章,BGP---边界网关协议
开发语言·网络·php
~央千澈~3 天前
域名与官网的迷思:数字身份认证的全球困境与实践解方-优雅草卓伊凡
开发语言·php