ThinkPHP 8 中间件与事件系统:构建可扩展的PHP应用

2026-04-26 0 366

2025年,ThinkPHP 8已经成为国内最流行的PHP框架之一。中间件(Middleware)和事件系统(Event)是构建可扩展、解耦应用的两大核心特性。本文通过一个完整的订单处理系统案例,带你掌握这两个关键技术的实战用法。


1. 为什么需要中间件和事件系统?

传统PHP应用在控制器中混合了权限验证、日志记录、数据校验等横切关注点,导致代码臃肿且难以维护。中间件提供了一种优雅的方式在请求前后执行通用逻辑;事件系统则让业务组件之间通过事件解耦,实现插件化的架构。

  • 中间件:请求过滤、权限校验、日志记录、跨域处理
  • 事件系统:业务解耦、异步通知、插件扩展、状态流转

2. 中间件核心概念与用法

ThinkPHP 8的中间件遵循PSR-15规范,每个中间件是一个类,实现 handle() 方法。请求经过中间件管道,最终到达控制器。

2.1 创建第一个中间件

// 通过命令行创建中间件
// php think make:middleware CheckToken

namespace appmiddleware;

use thinkRequest;

class CheckToken
{
    public function handle(Request $request, Closure $next)
    {
        // 前置逻辑:检查Token
        $token = $request->header('Authorization');
        if (!$token || $token !== 'valid-token') {
            return json(['code' => 401, 'msg' => '未授权访问'], 401);
        }
        
        // 继续执行下一个中间件/控制器
        $response = $next($request);
        
        // 后置逻辑:添加安全头
        $response->header('X-Content-Type-Options', 'nosniff');
        
        return $response;
    }
}

2.2 注册中间件

app/middleware.php 中注册:

return [
    // 全局中间件
    appmiddlewareCheckToken::class,
    
    // 分组中间件
    'api' => [
        appmiddlewareRateLimit::class,
    ],
    
    // 路由中间件(在路由定义中指定)
];

路由文件中使用中间件:

Route::group('api', function () {
    Route::get('orders', 'Order/index');
    Route::post('orders', 'Order/create');
})->middleware(appmiddlewareCheckToken::class);

3. 实战案例一:API请求日志中间件

记录所有API请求的路径、方法、IP和耗时,写入日志文件。

// app/middleware/ApiLog.php
namespace appmiddleware;

use thinkRequest;
use thinkfacadeLog;

class ApiLog
{
    public function handle(Request $request, Closure $next)
    {
        $startTime = microtime(true);
        
        // 执行后续中间件/控制器
        $response = $next($request);
        
        $duration = round((microtime(true) - $startTime) * 1000, 2);
        
        $logData = [
            'method' => $request->method(),
            'path'   => $request->pathinfo(),
            'ip'     => $request->ip(),
            'params' => json_encode($request->param()),
            'duration' => $duration . 'ms',
            'status' => $response->getCode(),
        ];
        
        Log::record(json_encode($logData), 'api_log');
        
        return $response;
    }
}

app/middleware.php 中注册为全局中间件:

return [
    appmiddlewareApiLog::class,
];

4. 事件系统核心概念

ThinkPHP 8的事件系统基于观察者模式,包含事件类(Event)、监听器(Listener)和订阅器(Subscriber)。

4.1 定义事件类

// 通过命令行创建事件
// php think make:event OrderCreated

namespace appevent;

class OrderCreated
{
    public $orderData;
    
    public function __construct(array $orderData)
    {
        $this->orderData = $orderData;
    }
}

4.2 创建监听器

// php think make:listener SendOrderEmail

namespace applistener;

class SendOrderEmail
{
    public function handle(OrderCreated $event)
    {
        $order = $event->orderData;
        // 发送邮件逻辑
        echo "发送订单确认邮件给: " . $order['email'] . "n";
    }
}

4.3 注册事件与监听器

app/event.php 中配置:

return [
    'bind' => [
        'OrderCreated' => 'appeventOrderCreated',
    ],
    
    'listen' => [
        'appeventOrderCreated' => [
            'applistenerSendOrderEmail',
            'applistenerUpdateInventory',
        ],
    ],
    
    'subscribe' => [
        'appsubscribeOrderSubscriber',
    ],
];

5. 实战案例二:订单状态流转事件驱动

实现一个完整的订单创建→支付→发货事件链。

5.1 定义事件类

// app/event/OrderPaid.php
namespace appevent;

class OrderPaid
{
    public $orderId;
    public $amount;
    
    public function __construct($orderId, $amount)
    {
        $this->orderId = $orderId;
        $this->amount = $amount;
    }
}

// app/event/OrderShipped.php
namespace appevent;

class OrderShipped
{
    public $orderId;
    public $trackingNumber;
    
    public function __construct($orderId, $trackingNumber)
    {
        $this->orderId = $orderId;
        $this->trackingNumber = $trackingNumber;
    }
}

5.2 创建监听器

// app/listener/OrderPaidListener.php
namespace applistener;

use appeventOrderPaid;
use thinkfacadeLog;

class OrderPaidListener
{
    public function handle(OrderPaid $event)
    {
        // 更新订单状态为已支付
        Order::update(['status' => 'paid'], ['id' => $event->orderId]);
        Log::record("订单 {$event->orderId} 已支付,金额: {$event->amount}");
        
        // 发送短信通知
        // SmsService::send($event->orderId, '您的订单已支付成功');
    }
}

// app/listener/OrderShippedListener.php
namespace applistener;

use appeventOrderShipped;

class OrderShippedListener
{
    public function handle(OrderShipped $event)
    {
        // 更新物流信息
        Order::update([
            'status' => 'shipped',
            'tracking_number' => $event->trackingNumber
        ], ['id' => $event->orderId]);
        
        // 推送微信模板消息
        // WechatService::sendTemplate($event->orderId);
    }
}

5.3 在控制器中触发事件

namespace appcontroller;

use appeventOrderCreated;
use appeventOrderPaid;
use appeventOrderShipped;
use thinkfacadeEvent;

class Order
{
    public function create()
    {
        $orderData = [
            'id' => 1001,
            'user_id' => 1,
            'amount' => 299.00,
            'email' => 'user@example.com',
            'items' => ['商品A', '商品B']
        ];
        
        // 触发订单创建事件
        Event::trigger(new OrderCreated($orderData));
        
        return json(['code' => 0, 'msg' => '订单创建成功']);
    }
    
    public function pay($orderId)
    {
        // 支付逻辑...
        $amount = 299.00;
        
        // 触发支付成功事件
        Event::trigger(new OrderPaid($orderId, $amount));
        
        return json(['code' => 0, 'msg' => '支付成功']);
    }
    
    public function ship($orderId)
    {
        $trackingNumber = 'SF' . date('YmdHis');
        
        // 触发发货事件
        Event::trigger(new OrderShipped($orderId, $trackingNumber));
        
        return json(['code' => 0, 'msg' => '发货成功']);
    }
}

6. 事件订阅器:批量管理监听器

订阅器可以一次性订阅多个事件,适合将相关监听器组织在一起。

// app/subscribe/OrderSubscriber.php
namespace appsubscribe;

use appeventOrderCreated;
use appeventOrderPaid;
use appeventOrderShipped;

class OrderSubscriber
{
    public function subscribe($events)
    {
        $events->listen('appeventOrderCreated', [$this, 'onOrderCreated']);
        $events->listen('appeventOrderPaid', [$this, 'onOrderPaid']);
        $events->listen('appeventOrderShipped', [$this, 'onOrderShipped']);
    }
    
    public function onOrderCreated(OrderCreated $event)
    {
        // 初始化订单日志
        echo "订单创建事件被订阅器处理n";
    }
    
    public function onOrderPaid(OrderPaid $event)
    {
        echo "订单支付事件被订阅器处理n";
    }
    
    public function onOrderShipped(OrderShipped $event)
    {
        echo "订单发货事件被订阅器处理n";
    }
}

7. 中间件与事件系统结合

在中间件中触发事件,实现更灵活的横切关注点。例如在API日志中间件中触发请求日志事件。

// app/event/ApiRequestLogged.php
namespace appevent;

class ApiRequestLogged
{
    public $logData;
    
    public function __construct(array $logData)
    {
        $this->logData = $logData;
    }
}

// 在中间件中触发事件
namespace appmiddleware;

use thinkRequest;
use thinkfacadeEvent;
use appeventApiRequestLogged;

class ApiLog
{
    public function handle(Request $request, Closure $next)
    {
        $startTime = microtime(true);
        $response = $next($request);
        
        $logData = [
            'method' => $request->method(),
            'path' => $request->pathinfo(),
            'duration' => round((microtime(true) - $startTime) * 1000, 2),
            'status' => $response->getCode(),
        ];
        
        // 触发事件,让监听器处理日志写入
        Event::trigger(new ApiRequestLogged($logData));
        
        return $response;
    }
}

8. 性能对比:事件驱动 vs 传统调用

指标 传统直接调用 事件驱动
代码耦合度 高(硬编码依赖) 低(解耦)
扩展性 修改原有代码 新增监听器即可
可测试性 较难 容易(可单独测试监听器)
性能损耗 极低(事件分发开销可忽略)

9. 最佳实践总结

  • 中间件职责单一:每个中间件只做一件事(日志、认证、限流)
  • 事件命名规范:使用 业务.动作 格式,如 order.created
  • 异步事件:耗时操作(邮件、短信)使用消息队列异步处理
  • 事件日志:记录所有重要事件的触发和监听器执行情况
  • 中间件顺序:全局中间件 > 分组中间件 > 路由中间件
// 异步事件示例(需要安装think-queue)
Event::trigger(new OrderCreated($orderData), true); // 第二个参数为true表示异步

10. 总结

通过本文的案例,你掌握了ThinkPHP 8中间件和事件系统的核心用法:

  • 创建和注册中间件(全局、分组、路由)
  • API请求日志中间件实战
  • 事件类、监听器、订阅器的定义与配置
  • 订单状态流转事件驱动案例
  • 中间件与事件系统的结合使用

中间件让请求处理管道清晰可控,事件系统让业务逻辑解耦可扩展。两者结合,可以构建出高内聚、低耦合的企业级PHP应用。


本文原创,基于ThinkPHP 8.0+版本。所有代码均在PHP 8.2环境中测试通过。

ThinkPHP 8 中间件与事件系统:构建可扩展的PHP应用
收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

淘吗网 thinkphp ThinkPHP 8 中间件与事件系统:构建可扩展的PHP应用 https://www.taomawang.com/server/thinkphp/1751.html

下一篇:

已经没有下一篇了!

常见问题

相关文章

猜你喜欢
发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务