博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Laravel 中间件
阅读量:7237 次
发布时间:2019-06-29

本文共 7150 字,大约阅读时间需要 23 分钟。

Laravel 中间件

代码展示

protected function sendRequestThroughRouter($request){    # $this->app->instance('request', $request);    # Facade::clearResolvedInstance('request');    # $this->bootstrap();    return (new Pipeline($this->app))                ->send($request)                ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)                ->then($this->dispatchToRouter());      // $this->dispatchToRouter(),后期继续}new \Illuminate\Routing\Pipeline($this->app):public function __construct(Container $container = null){    $this->container = $container;}public function send($passable){    $this->passable = $passable;    return $this;}public function through($pipes){    ####################################################################################    #    $this->middleware = [                                                         #    #        \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,    #    #        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,           #    #        \App\Http\Middleware\TrimStrings::class,                                  #    #        \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,  #    #    ];                                                                            #    ####################################################################################    $this->pipes = is_array($pipes) ? $pipes : func_get_args();    return $this;}// 中间件的本质public function then(Closure $destination){    $pipeline = array_reduce(        array_reverse($this->pipes), $this->carry(), $this->prepareDestination($destination)    );    // 上面操作完之后返回一个匿名函数,接受一个参数    return $pipeline($this->passable);}// 注意这个是子类里面会调用的父carry,区别在于子类加入了异常处理protected function carry(){    // 接受匿名函数$stack参数和$pipe参数,返回匿名函数,再将此匿名函数作为第一个参数$stack迭代传入。    return function ($stack, $pipe) {        return function ($passable) use ($stack, $pipe) {            if ($pipe instanceof Closure) {                return $pipe($passable, $stack);            } elseif (! is_object($pipe)) {                list($name, $parameters) = $this->parsePipeString($pipe);                $pipe = $this->getContainer()->make($name);                $parameters = array_merge([$passable, $stack], $parameters);            } else {                $parameters = [$passable, $stack];            }            // 中间件作用是提供了一种方便的机制来过滤进入应用的 HTTP 请求            // $this->method默认为handle,可通过via方法进行设置            return $pipe->{$this->method}(...$parameters);        };    };}protected function parsePipeString($pipe){    // 不带参数的pipe(class)或带参数(参数以,分割)的pipe(class:param1,param2,param3...)    list($name, $parameters) = array_pad(explode(':', $pipe, 2), 2, []);    if (is_string($parameters)) {        $parameters = explode(',', $parameters);    }    // $parameters为[]数组或[param1,param2,param3...]    return [$name, $parameters];}protected function prepareDestination(Closure $destination){    return function ($passable) use ($destination) {        return $destination($passable);    };}

前置条件

  1. array_reduce接受三个参数,第一个参数接收数组,第二个参数函数名(也可以是匿名函数,函数有两个参数,分别代表$result和$item),第三个参数(可选),该参数将被当成是数组中的第一个值来处理,或者如果数组为空的话就作为最终返回值。

  2. 匿名函数也叫闭包函数(closures),允许临时创建一个没有指定名称的函数,通过 Closure 类来实现的。

  3. 当对闭包函数进行赋值时,PHP 便会自动将此种表达式转换成内置类 Closure 的对象对象在进行赋值。

  4. 当闭包函数使用到 use 使用外部数据时,会在 Closure 对象生成一个 static 属性数组进行存放。

  5. 当闭包函数使用到参数时,会在 Closure 对象生成一个 parameter 属性数组进行存放。

public function then(Closure $destination)    {        $pipeline = array_reduce(            array_reverse($this->pipes), $this->carry(), $this->prepareDestination($destination)        );        return $pipeline($this->passable);    }

生成最终匿名函数的过程:

array_reduce执行第一次时得到如下简化的匿名函数返回,将会继续作为第一个参数进行迭代:                object(Closure)#id (1) {          ["static"]=>          array(2) {            ["stack"]=>            object(Closure)#1 (0) { // $this->prepareDestination($destination)            }            ["pipe"]=>            string(15) "Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull"          }        }    第二次:        object(Closure)#id (1) {          ["static"]=>          array(2) {            ["stack"]=>            object(Closure)#id (1) {              ["static"]=>              array(2) {                ["stack"]=>                object(Closure)#1 (0) { // $this->prepareDestination($destination)                }                ["pipe"]=>                string(15) "Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull"              }            }            ["pipe"]=>            string(15) "App\Http\Middleware\TrimStrings"          }        }    第三次:        object(Closure)#id (1) {          ["static"]=>          array(2) {            ["stack"]=>            object(Closure)#id (1) {              ["static"]=>              array(2) {                ["stack"]=>                object(Closure)#id (1) {                  ["static"]=>                  array(2) {                    ["stack"]=>                    object(Closure)#1 (0) { // $this->prepareDestination($destination)                    }                    ["pipe"]=>                    string(15) "Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull"                  }                }                ["pipe"]=>                string(15) "App\Http\Middleware\TrimStrings"              }            }            ["pipe"]=>            string(15) "Illuminate\Foundation\Http\Middleware\ValidatePostSize"          }        }

依次类推,最终得到一个匿名函数如下(接受一个参数,此匿名函数内部使用上面递归形式的$pipe和$stack)。

function ($passable) {        if ($pipe instanceof Closure) {            return $pipe($passable, $stack);        } elseif (! is_object($pipe)) {            list($name, $parameters) = $this->parsePipeString($pipe);            $pipe = $this->getContainer()->make($name); // 实例化middleware            $parameters = array_merge([$passable, $stack], $parameters);        } else {            $parameters = [$passable, $stack];        }        return $pipe->{$this->method}(...$parameters);  // 语法糖模式,因为middleware参数可有可无    };

最终匿名函数的调用过程(从最外层开始,这就是前面为什么要array_reverse,一层一层往里拨,整体上的处理是:$pipe若是匿名函数,直接调用。若是字符串,则解析成对应的类和参数,make类,再组成参数数组。最后调用$pipe->handle)

最外层($pipe=Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode):    (new \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode)->handle($passable, $stack)    执行完前置操作后,调用$stack($passable),继续进行下一层    下一层($pipe=Illuminate\Foundation\Http\Middleware\ValidatePostSize):    (new \Illuminate\Foundation\Http\Middleware\ValidatePostSize)->handle($passable, $stack)    执行完前置操作后,调用$stack($passable),继续进行下一层    **以此类推,当每层中间件的前置任务全部完成,即递归执行到最里面一层(路由分发,解析请求,返回响    应),再由最内层一层一层往回走,执行每层中间件的后置任务。至此,返回本次请求的响应。**

最内层(即路由分发,解析请求,返回响应)的操作代码展示,后续分析:即执行$destination($passable)匿名函数,位于下面方法中。

protected function prepareDestination(Closure $destination)    {        return function ($passable) use ($destination) {            return $destination($passable);        };    }    $destination:    protected function dispatchToRouter()    {        return function ($request) {            $this->app->instance('request', $request);            return $this->router->dispatch($request);        };    }

说明:

所有的后置操作,都是执行到最内层,递归往回走时才会执行逐层执行。

转载地址:http://lagfm.baihongyu.com/

你可能感兴趣的文章
我的友情链接
查看>>
微信公众平台开发入门教程_无需整理
查看>>
Ubuntu15.04下搭建LNMP环境 - 无需整理
查看>>
DNS(域名服务器)实验:
查看>>
基于LVS-DR群集模式+keepalived实现高可用
查看>>
十万个为什么之我的一些技术疑问
查看>>
数据迁移保存的路径斜杠被消除解决方案
查看>>
如何修复MYISAM表
查看>>
Azure VM 实现负载均衡
查看>>
Common Techniques to Improve Shadow Depth Maps
查看>>
2011年11月11日成都微软虚拟化研讨会
查看>>
如何通过DB link进行远程过程或函数调用
查看>>
Linux命令--群组管理相关
查看>>
互联网泄密门蔓延:客户资料银行内部几乎透明
查看>>
表单以get方式提交出现中文乱码解决办法
查看>>
在cisco交换机上禁止某个特定MAC地址转发
查看>>
Exchange 2010之灾难恢复
查看>>
我的友情链接
查看>>
Mac commands
查看>>
关于清理distribution数据库过期数据
查看>>