PHP 怎么PHP 中间件执行

wen PHP项目 1

本文目录导读:

PHP 怎么PHP 中间件执行

  1. 核心执行机制:闭包传递
  2. 手写一个简单的中间件运行机制
  3. 主流框架的实现对比
  4. 中间件的常见应用场景(前端视角)
  5. 执行流程总结

在 PHP 中,中间件的执行通常遵循 洋葱模型(Onion Model)管道模式(Pipeline Pattern),核心思想是:请求依次通过中间件层,每一层可以决定是否继续传递请求(或处理响应返回)。

下面我会从基础概念到手写实现、再到主流框架(Laravel/ThinkPHP)的对比来说明。


核心执行机制:闭包传递

绝大多数 PHP 中间件的核心代码只有一句话:

// 伪代码核心: next 是一个回调,指向下一个中间件或最终处理
return $next($request);
  • 当一个中间件调用 $next($request) 时,程序会进入下一个中间件
  • 当所有中间件都执行完后,最终处理(路由/控制器)返回响应,响应再原路返回经过每个中间件的后续代码。

手写一个简单的中间件运行机制

为了彻底搞懂,我们可以手动实现:

步骤 1:定义中间件接口

interface Middleware {
    public function handle($request, \Closure $next);
}

步骤 2:实现几个中间件

class AuthMiddleware implements Middleware {
    public function handle($request, \Closure $next) {
        echo "Auth 中间件:开始\n";
        // 条件不通过,直接返回,不再向下
        // if(!$request->hasToken) return "403 未授权";
        $response = $next($request);
        echo "Auth 中间件:结束\n";
        return $response;
    }
}
class LogMiddleware implements Middleware {
    public function handle($request, \Closure $next) {
        echo "Log 中间件:开始\n";
        $response = $next($request);
        echo "Log 中间件:结束\n";
        return $response;
    }
}

步骤 3:构建管道执行

class Pipeline {
    private $middlewares = [];
    public function add(Middleware $middleware) {
        $this->middlewares[] = $middleware;
    }
    public function run($request, \Closure $finalHandler) {
        // 关键:从最后一个中间件往前构建闭包链
        $stack = $finalHandler;
        // 反转数组,从最后一个中间件开始包裹
        foreach(array_reverse($this->middlewares) as $middleware) {
            $stack = function($request) use ($middleware, $stack) {
                return $middleware->handle($request, $stack);
            };
        }
        // 执行最终构建的闭包
        return $stack($request);
    }
}

步骤 4:测试

$pipeline = new Pipeline();
$pipeline->add(new AuthMiddleware());
$pipeline->add(new LogMiddleware());
$request = "some request data";
$result = $pipeline->run($request, function($req) {
    echo "--- 核心业务处理 ---\n";
    return "处理结果";
});
echo "\n最终返回: " . $result;

输出结果

Auth 中间件:开始
Log 中间件:开始
--- 核心业务处理 ---
Log 中间件:结束
Auth 中间件:结束
最终返回: 处理结果

顺序执行逻辑:Auth -> Log -> 核心 -> Log -> Auth

这完全符合洋葱模型的 先入后出(Stack) 特性。


主流框架的实现对比

Laravel 中间件

Laravel 使用 Symfony 的 HttpKernelInterface + 管道模式。

  • 定义:app/Http/Kernel.php 中的 $middleware$routeMiddleware
  • 执行流程:
// 核心代码片段(简化)
$response = (new Pipeline($this->app))
    ->send($request)
    ->through($middleware)
    ->then(function ($request) use ($router) {
        return $router->dispatch($request);
    });
  • 单个中间件:
class CheckAge {
    public function handle($request, \Closure $next) {
        if ($request->age < 18) {
            return redirect('home'); // 中断
        }
        return $next($request); // 继续
    }
}

Laravel 还支持中间件组web/api)、Terminable Middleware(请求结束后执行清理)。

ThinkPHP 6 中间件

ThinkPHP的中间件机制类似,定义在 config/middleware.php

  • 定义:
class Hello {
    public function handle($request, \Closure $next) {
        // 前置操作
        $response = $next($request);
        // 后置操作
        return $response;
    }
}
  • 调用时通过 think\Pipeline 类实现,和手写原理基本一致。

中间件的常见应用场景(前端视角)

如果你的工作涉及 PHP 后端,中间件最常用在以下场景:

场景 中间件作用 原生/框架解决方案
用户认证 未登录跳转登录页 auth中间件(Laravel)
think\middleware\AllowCrossDomain
CORS跨域 添加 Access-Control-* App\Http\Middleware\Cors
限流 防止DDOS/刷接口 throttle:60,1(60次/分钟)
请求日志 记录所有API请求参数和时间 自定义中间件
响应压缩 gzip \App\Http\Middleware\CompressResponse

执行流程总结

[请求 进来]
   ↓
中间件1 开始(前置代码)
   ↓ 调用 $next($request)
中间件2 开始(前置代码)
   ↓ 调用 $next($request)
...
最终控制器/业务处理 (返回响应)
...
   ↑ $response 返回
中间件2 结束(后置代码)
   ↑ $response 返回
中间件1 结束(后置代码)
   ↑
[响应 返回给客户端]

关键点

  • $next($request) 就像 “放行”按钮 —— 不调用就卡住(中断请求)。
  • 响应的后置处理代码的执行顺序和中间件添加顺序相反(栈的特性)。
  • 框架通常用 Pipeline 类将多个中间件压扁成一个闭包来依次执行。

PHP 中间件的核心思想就是 装饰器模式 + 闭包传递,通过把行为分层包装,实现了高度可解耦的请求处理流程。

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