请求处理管道个人理解

学前必备知识点:闭包(Closure),array_reduce(),array_reverse()
可选进阶知识点:装饰者模式

简易模拟请求处理管道

<?php

/**
 * Interface Step
 */
interface Step {
    /**
     * @param Closure $next
     * @return mixed
     */
    public static function go(Closure $next);
}

/**
 * 中间件1
 * Class FirstStep
 */
class FirstStep implements Step {
    /**
     * @param Closure $next
     */
    public static function go (Closure $next)
    {
        echo "开启session,获取数据...".'<br>';
        $next();
        echo "保存数据,关闭SESSION...".'<br>';
    }
}

/**
 * 中间件2
 * Class SecondStep
 */
class SecondStep implements Step {
    /**
     * @param Closure $next
     */
    public static function go(Closure $next)
    {
        echo "检测用户权限";
        $next();
    }
}

/**
 * array_reduce自定义函数
 * @param $step
 * @param $className
 * @return Closure
 */
function goFun($step, $className)
{
    return function() use($step,$className)
    {
        return $className::go($step);
    };
}

/**
 * 模拟执行处理管道
 */
function then()
{
    $steps = ["FirstStep","SecondStep"];
    $prepare = function() { echo "请求向路由器传递,返回响应...".'<br>';};
    $go = array_reduce($steps,"goFun",$prepare);
    //这里是关键,第一个是要处理的数组,第二个是自定义回调函数,
    //第三个是可选参数,为初始化参数,被当作array_reduce中第一个值来处理,若数组为空则作为返回值。
    //var_dump($go);
    //$test = new Reflection($go);
    $go();
}

then();

/* 
 * 详细解析
 * 定义步骤一,步骤二
 * 定义初始化参数$preapres
 * array_reduce执行过程:
 * 1.生成闭包函数function()
    {
        FirstStep::go($prepares);
    };
 * 2.生成function()
    {
        SecondStep::go(function()
             {
                FirstStep::go($prepares);
             };);
    };
 * 最终执行顺序是每个类中的go方法:SecondStep,First的第一个步骤,$prepares,First的第二个步骤,可以看到与数组['FirstStep,'SecondStep']的顺序反过来了
 * 在实际Laravel的管道中用了array_reverse,使得执行顺序与数组定义的顺序一致
 * 这里看起来有点类似递归,先一层一层进入,再把执行权一层一层转回去
在闭包中传入闭包…..
执行闭包 , 在闭包的语句里再执行传入的闭包
 * */

laravel中的请求处理管道

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

class VerifyCsrfToken implements Middleware
{
    public static function handle(Closure $next)
    {
        echo "验证csrf-token.......";
        $next();
    }
}

class ShareErrorsFromSession implements Middleware
{
    public static function handle(Closure $next)
    {
        echo "如果session中有errors变量,共享他....";
        $next();
    }
}

class StartSession implements Middleware
{
    public static function handle(Closure $next)
    {
        echo "开启session,获取数据....";
        $next();
        echo "保存数据,关闭session..";

    }
}

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

class EncryptCookies implements Middleware
{
    public static function handle(Closure $next)
    {
        echo "对输入请求的cookie进行解密...";
        $next();
        echo "对输出响应的cookie进行加密...";
    }
}

class CheckForMaintenanceMode implements Middleware
{
    public static function handle(Closure $next)
    {
        echo "确定当前程序是否处于维护状态...";
        $next();
    }
}

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

function then()
{
    $pipes= [
        "CheckForMaintenanceMode",
        "EncryptCookies",
        "AddQueuedCookiesToResponse",
        "StartSession",
        "ShareErrorsFromSession",
        "VerifyCsrfToken"
    ];
    $firstSlice = function () {
        echo "请求向路由器传递,返回响应....";
    };
    $pipes = array_reverse($pipes);
    call_user_func(
        array_reduce($pipes, getSlice(), $firstSlice)
    );
}

then();

/*
 * 先reverse把数组倒转过来
 * 于是先生成VerifyCsrfTokenLLhanle($firstSlice);
 * 再生成ShareErrorsFromSession::handle($上一步生成的闭包);
 * ......
 * ....
 * 最后生成CheckForMaintenanceMode::handle($上一步生成的闭包);
 *
 * 于是执行顺序就变为脑图
 *
 */

执行顺序脑图

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 2

laravel 框架关键技术解析 ? :joy:

3年前 评论

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