PHP项目责任链与中间件

wen PHP项目 137

本文目录导读:

PHP项目责任链与中间件

  1. 核心概念对比
  2. 责任链模式(Chain of Responsibility)
  3. 中间件(Middleware)
  4. 关键区别总结
  5. 实际项目中的选择建议
  6. 性能与维护注意事项

这是一个非常好的技术问题,在 PHP 项目中,责任链模式(Chain of Responsibility) 和 中间件(Middleware) 本质上都是面向切面编程和请求预处理的实现方式,但它们在设计理念、实现粒度和典型应用场景上有显著区别。


核心概念对比

维度 责任链模式 中间件
本质 设计模式(GoF) 架构风格(受中间件框架启发)
传递机制 沿着链条逐个处理,直到某个节点处理完或终止 类似“洋葱圈”模型,层层包裹,处理完返回
控制反转 链上节点决定是否继续传递 由中间件调用 $next($request) 触发下一个
典型应用 日志、权限校验、数据过滤 Laravel 路由中间件、PSR-15 中间件
执行顺序 顺序执行,可中断 入栈(前置)→ 核心处理 → 出栈(后置)

责任链模式(Chain of Responsibility)

适用场景

  • 多个处理器按顺序尝试处理同一个请求
  • 每个处理器可独立决定是否处理或传递给下一个
  • 请求的唯一处理者不确定,由运行时决定

经典实现(PHP 示例)

// 抽象处理器
abstract class Handler
{
    protected ?Handler $next = null;
    public function setNext(Handler $handler): Handler
    {
        $this->next = $handler;
        return $handler; // 返回下一个,便于链式调用
    }
    abstract public function handle(Request $request): ?Response;
}
// 具体处理器:日志
class LoggingHandler extends Handler
{
    public function handle(Request $request): ?Response
    {
        // 前置处理
        echo "[LOG] 记录请求: {$request->uri}\n";
        // 传递给下一个(如有)
        if ($this->next) {
            return $this->next->handle($request);
        }
        return null;
    }
}
// 具体处理器:权限检查
class AuthHandler extends Handler
{
    public function handle(Request $request): ?Response
    {
        if (!$request->hasToken()) {
            echo "[AUTH] 未授权,终止链!\n";
            return new Response(403, 'Forbidden'); // 阻断链条
        }
        echo "[AUTH] 用户已验证\n";
        if ($this->next) {
            return $this->next->handle($request);
        }
        return null;
    }
}
// 使用
$request = new Request('/api/data', ['token' => 'abc']);
$chain = new LoggingHandler();
$chain->setNext(new AuthHandler())
      ->setNext(new ValidationHandler());
$response = $chain->handle($request);

特点:

  • 每个处理器内部手动调用 $this->next->handle()
  • 可以在任意节点决定返回(中断链条)

中间件(Middleware)

适用场景

  • 请求/响应需要经过一系列预处理和后处理(如 CSRF 保护、Session 启动、CORS 头)
  • 所有中间件都需要执行,顺序重要
  • 需要“双向”处理(进去时做前置,返回时做后置)

洋葱模型(Laravel/PSR-15 风格)

// PSR-15 中间件接口
interface MiddlewareInterface
{
    public function process(
        Request $request,
        RequestHandlerInterface $handler
    ): Response;
}
// 具体中间件
class CorsMiddleware implements MiddlewareInterface
{
    public function process(Request $request, RequestHandlerInterface $handler): Response
    {
        // 前置处理
        $response = $handler->handle($request);  // 调用下一个中间件
        // 后置处理
        $response = $response->withHeader('Access-Control-Allow-Origin', '*');
        return $response;
    }
}
// 简单实现的核心处理器
class CoreHandler implements RequestHandlerInterface
{
    public function handle(Request $request): Response
    {
        // 真正的业务逻辑
        return new Response(200, 'Hello');
    }
}
// 中间件调度器
class MiddlewareDispatcher implements RequestHandlerInterface
{
    private array $middlewareQueue;
    private int $index = 0;
    public function __construct(array $middlewareQueue)
    {
        $this->middlewareQueue = $middlewareQueue;
    }
    public function handle(Request $request): Response
    {
        if ($this->index < count($this->middlewareQueue)) {
            $middleware = $this->middlewareQueue[$this->index];
            $this->index++;
            return $middleware->process($request, $this); // 递归调用
        }
        // 所有中间件处理完毕,执行核心处理
        return new Response(200, 'Final Response');
    }
}

关键区别总结

特性 责任链 中间件
调用方式 手动调用 $next->handle() 回调/闭包 $next($request)
双向性 一般只有前置处理(可做后置但麻烦) 天然支持前后置处理(洋葱圈)
中断机制 任意节点可以返回(不调用 $next) 通过异常抛出或直接返回 Response 中断
代码组织 链式结构,顺序由 setNext 决定 管道式结构,顺序由数组/栈决定
框架支持 较少直接提供,需手动实现 Laravel、Slim、Symfony 内置

实际项目中的选择建议

选用责任链模式(手动实现)

  • 当你需要运行时动态组装处理器,且处理器可能选择性跳过
  • 典型的如:验证链(用户输入 → 格式校验 → 业务校验 → 数据库校验)
  • 或者当每个处理器都**可独立成功”,不需要统一的前后处理

选用中间件(推荐框架内置)

  • 在现代化 PHP 框架(Laravel、Symfony、Slim)中,始终优先使用中间件
  • 因为框架已经为你实现了:
    • 依赖注入
    • 路由匹配
    • 异常处理包装
    • 调度器(Dispatcher)

混合使用

有时两者可以结合:

Request → AuthMiddleware → LogMiddleware → ChainHandler(责任链) → Controller

性能与维护注意事项

  1. 中间件过多会线性增加请求处理时间,建议控制在 10 个以内
  2. 责任链中不要做同步 IO 操作,每个节点应快速返回
  3. 注意执行顺序:
    • 责任链中:handle() 的调用顺序决定
    • 中间件中:通常先注册的后执行(Laravel 中是先注册的先出栈)

项目规模 推荐方式
小项目 / 自建框架 责任链模式(更灵活)
使用 Laravel/Symfony 中间件(框架原生支持)
需要双向处理(前后置) 中间件
需要动态跳过处理器 责任链
两者二选一 选中间件,更符合现代 PHP 生态

抱歉,评论功能暂时关闭!

友情链接攻略窝 · 礼包窝 · 配置窝 · 换算窝 · 算法窝 · 查文窝 · 手册窝 · 问答窝 · 全文搜 · 手册库
相关站点礼包窝 · 查文窝