Laravel请求处理管道理解

必备知识点:
闭包(Closure)array_reduce()函数array_reverse()函数call_user_func()函数
装饰者模式
资料:
《Laravel框架关键技术解析》
相关博客

示例代码:

interface Middleware
{
    public static function handle(Closure $next);
}

class VerifyCsrfToken implements Middleware
{
    public static function handle(Closure $next)
    {
        echo "验证 CSRF Token<br />";
        $next();
    }
}

class ShareErrorsFromSession implements Middleware
{
    public static function handle(Closure $next)
    {
        echo "如果 Session中有'errors'变量, 则共享它<br />";
        $next();
    }
}

class StartSession implements Middleware
{
    public static function handle(Closure $next)
    {
        echo "开启 Session,获取会话数据<br />";
        $next();
        echo "保存会话数据,关闭 Session<br />";
    }
}

class AddQueuedCookiesToResponse implements Middleware
{
    public static function handle(Closure $next)
    {
        $next();
        echo "添加下一次请求需要的cookie".'<br>';
    }
}

class EncryptCookies implements Middleware
{
    public static function handle(Closure $next)
    {
        echo "对输入 Cookie 进行解密<br />";
        $next();
        echo "对输出 Cookie 进行加密";
    }
}

class CheckMaintenanceMode implements Middleware
{
    public static function handle(Closure $next)
    {
        echo "检测系统是否处于维护状态<br />";
        $next();
    }
}

function getSlice()
{
    return function ($stack, $pipe) {
        return function () use ($stack, $pipe) {
            return $pipe::handle($stack);
        };
    };
}

function then()
{
    $pipes = [
        CheckMaintenanceMode::class,
        EncryptCookies::class,
        AddQueuedCookiesToResponse::class,
        StartSession::class,
        ShareErrorsFromSession::class,
        VerifyCsrfToken::class,
    ];

    $firstSlice = function () {
        echo "请求向路由器传递,返回响应<br />";
    };
    $pipes = array_reverse($pipes);
    call_user_func(
        array_reduce($pipes, getSlice(), $firstSlice)
    );
}

then();

执行流程

  1. 刚开始执行,首先array_reservse()函数将$pipes数组倒序反转,至于为什么需要反转后面再说明。
  2. array_reduce()将回调函数getSlice()迭代地作用到$pipes数组中的每一个单元中,而array_reduce()设置了初始值,则第一个执行的是$firstSlice这个函数。
  3. 第一个执行的是$firstSlice这个函数,所以
    function ($firstSlice, VerifyCsrfToken::class) {
     return function ($firstSlice, VerifyCsrfToken::class) {
         return VerifyCsrfToken::handle($firstSlice);
     }
    }
  4. 执行到第二个是时候是
    function (VerifyCsrfToken::class, ShareErrorsFromSession::class) {
     return function (VerifyCsrfToken::class, ShareErrorsFromSession::class) {
         return ShareErrorsFromSession::handle(function ($firstSlice, VerifyCsrfToken::class) {
             return function ($firstSlice, VerifyCsrfToken::class) {
                 return VerifyCsrfToken::handle($firstSlice);
             }
         });
     }
    }
  5. 以此类推….
    最后变成这样:
    function (){
     return CheckMaintenanceMode::handle(function (){
         return EncryptCookies::handle(function (){
             return AddQueuedCookiesToResponse::handle(function (){
                 return StartSession::handle(function (){
                     return ShareErrorsFromSession::handle(function (){
                         return VerifyCsrfToken::handle(function (){
                             echo "请求向路由器传递,返回响应<br />";
                         })
                     })
                 });
             });
         });
     });
    }
    执行到数组的最后一次,则是CheckMaintenanceMode::class,然后call_user_func()执行回调函数,先执行CheckMaintenanceMode::class,然后执行EncryptCookies::class,执行顺序则与未反转前的数组顺序完全相同,这也是为什么需要使用array_reservse()函数进行反转的原因。

    执行结果

    检测系统是否处于维护状态
    对输入 Cookie 进行解密
    开启 Session,获取会话数据
    如果 Session中有'errors'变量, 则共享它
    验证 CSRF Token
    请求向路由器传递,返回响应
    保存会话数据,关闭 Session
    添加下一次请求需要的cookie
    对输出 Cookie 进行加密
本作品采用《CC 协议》,转载必须注明作者和本文链接
lemon_lyue
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!