草稿 3pipeline

laravel 5.1 的pipeline

pipeline是在启动过程中的哪个环节这个得需要知道。
其实是在$kernel->handle($request);这部分中handle方法里面。handle方法就是捕获请求。它做了两个事情(其他的还没看到)。1、注册服务提供者。2、请求经过全局中间件。
这里只谈第二个 请求经过全局中间件。

Illuminate\Foundation\Http\kernel.php

public function handle($request){
    $this->enableHttpMethodParameterOverride();
    $response = $this->sendRequestThroughRouter($request);

    //省略捕获异常…
    return $response;
}
protected function sendRequestThroughRouter()
{
        //把请求实例绑定到用单例模式容器,array_reduce()的初始参数里面也写
        $this->app->instance('request', $request);
        // 清除已完成的请求
        Facade::clearResolveInstance('request');
        // 启动服务提供者,单独的一个篇章。
        $this->bootstrap();    
        // 管道            
        return (new Pipeline($this->app))
                ->send($request)
                ->through($this->app->shouldSkipMiddleware()?[]:$this->middleware)
                ->then($this->dispatchToRouter());
} 
//***就是这里
protected function dispachToRouter()
{
        return function($request) {
            //当前请求实例已经通过上面定义好的中间件,也就是说已经经过了(through)全局中间件。要说之与前的instance('request',$request) 的区别一个是没有经过中间件,这里是经过了中间件的情况的单例,具体我也不是太清楚。
            $this->app->instance('request', $request);
            // 这里就是分配给路由了,其他是请就路由的部分的功能。
            return    $this->router->dispatch($request);
        };
}

Illuminate\Pipeline\Pipeline.php(自己写的就是练习)

// 设置$request
public function send($possible)
{
        $this->possible = $possible;
        return    $this;
}
// 设置中间件
public function through($pipes)
{
        $this->pipes = is_array($pipes)?$pipes:fun_get_args();
        return $this;
}
// 运行包和穿透中间件操作
public function then($destination)
{
        $firstSlice = $this->firstSlice($destination);
        $pipes = array_reverse($this->pipes);
        return call_user_func(
                        array_reduce($pipes, $this->getSlice(), $firstSlice), $this->possible
        );
}

public function firstSlice($destination)
{
        return function($request) use ($destination){
            return $destination($request);
        }; 
}

public function getSlice()
{
        return function ($stack, $pipe) {
            //这个是包洋葱时候用到的
            return function($request) use ($stack, $pipe){
                    // ...code ,其实就是要变成下面的这样形式,这个是穿透洋葱的过程
                    // return $pipe::handle($stack);
            };
        };

}

Illuminate\Pipeline\Pipeline.php; laravel的pipeline

// kernel里面new Pipeline($this->app)时候用到
public function __construct(Container $container)
{
    $this->container = $container;
}
//设置request对象
public function send($passable)
{
    $this->passable = $passable;

    return $this;
}
// 设置中间件
public function through($pipes)
{
    $this->pipes = is_array($pipes) ? $pipes : func_get_args();

    return $this;
}
// 这里用到了包洋葱过程和穿透洋葱过程
public function then(Closure $destination)
{
    $firstSlice = $this->getInitialSlice($destination);

    $pipes = array_reverse($this->pipes);

    return call_user_func(
        // 这里面关键的两个地方,一个是array_reduce,看文档自行理解(看社区文档laravel之道理解其用法)。另一个$this->getSlice()。关键点看getSlice方法的返回值!返回值!返回值!。
        array_reduce($pipes, $this->getSlice(), $firstSlice), $this->passable
    );
}
// 第一次看的时候一头雾水,因为当时用匿名函数没多久也熟悉。匿名函数一个特性是懒惰加载,只有调用的时候才会执行
protected function getSlice()
{
    return function ($stack, $pipe) {
        return function ($passable) use ($stack, $pipe) {
            //
            if ($pipe instanceof Closure) {
                return call_user_func($pipe, $passable, $stack);
            } else {
                list($name, $parameters) = $this->parsePipeString($pipe);

                return call_user_func_array([$this->container->make($name), $this->method],
                                            array_merge([$passable, $stack], $parameters));
                //                                         handle方法
                // 其实就是$this->container->make($name)->{$this->method}($passable,$stack);
            }
        };
    };
}

protected function getInitialSlice(Closure $destination)
{
    return function ($passable) use ($destination) {
        //其实就是$destination($passable);
        return call_user_func($destination, $passable);
    };
}
  • 上面提到的包洋葱和穿透洋葱过程请点击这里

这里简单记下包洋葱和穿透洋葱的过程

分析包洋葱皮儿过程,下面的方法都是简写

// 设定一组中间件
$middleware = ['A', 'B', 'C'];
// 设置array_reduce第一个处理的参数即洋葱核心,即下面例子中处理的$fisrtSlice可不要以为是$middleware中的C。
$firstSlice = $this->getInitialSlice($destination);
// 源码then方法中的array_reduce()用法,包洋葱过程其实就是array_reduce干的事情。
array_reduce(array_reverse($middleware), $this->getSlise(), $firstSlise);

//看返回值!返回值!返回值!
protected function getInitialSlice(Closure $destination)
{
    return function($request) use ($destination){
        return $destination($request);
        };
}
// 简写:
protected function getSlice(){
    return function($stack, $pipe){
    //看到request是不是会头痛。看下面的例子
        return function($request) use ($stack, $pipe)
        {
            // code 这里其实不用关心,因为现在只是包洋葱的过程。
        };
    };
}

另一种写法

// array_reduce(array_reverse($middleware), getSlise(), $firstSlise);
array_reduce(
    ['C', 'B', 'A'], 
    // 每个元素要执行的函数
    function($stack, $pipe){
    //看到request是不是会头痛。看下面的例子
        return function($request) use ($stack, $pipe)
        {
            // code 这里其实不用关心,因为现在只是包洋葱的过程。
        }
    },
    // 第一个参数,如果没有返回值则作为返回值返回。相当于数组变成了['第一个参数','C', 'B', 'A'], 并且也是洋葱和核心。
    function($request) use ($destination){
        return $destination($request);
    }
);

把array_reduce理解为用函数getSlice()循环执行数组$middleware的元素。每次循环完以后给匿名函数赋个别名,方便理解。

第一次循环
C1 => function($request) use ($firstSlice, 'C'){}

第二次循环
B1 => function($request) use (C1, 'B'){}

第三次循环
A1 => function($request) use (B1, 'A'){}

最后返回的是A1也是一个匿名函数,包洋葱这个过程这里就结束了,下面是穿透洋葱的过程。

穿透(剥)洋葱皮儿,主要用到几个函数。

// 第一个函数
//就执行了call_user_func(),作用是调用匿名函数。第一个参数是要调用的匿名函数,其他参数都是传给这个匿名函数的参数。
call_user_func()

//第二个函数
protected function getSlice()
{
    return function ($stack, $pipe) {
            // 包的过程中到这里就结束了。穿透过程中是执行下面的代码
               return function ($passable) use ($stack, $pipe) {
               // 判断是否是匿名(回调)函数,这里只有$firstSlice是回调函数
                          if ($pipe instanceof Closure) {
                                return call_user_func($pipe, $passable, $stack);
                            } else {
                                // 这是获取中间件名称和后面的参数,参数具体效果我还不知道… - -!!
                                list($name, $parameters) = $this->parsePipeString($pipe);
                                // 实例话中间件,并调用handle方法。
                                // 传参数$passable:请求实例。其实是传过来的$request
                                // 传参数$stack 匿名(回调)函数 。上面说到的A1,B1,C1。
                                return call_user_func_array(
                                            [$this->container->make($name), $this->method],
                                            array_merge([$passable, $stack], $parameters)
                                            );

                            }
                };
    };
 }

// 第三个函数
// 如果你在laravel里面注册过中间件都会见到这个代码
public function handle($request, Closure $next)
{
    //中间件自己的code...
    return $next($request);
}

穿透(剥)皮儿过程

上面包洋葱皮最后得到的结果是A1。 就可以理解成call_user_func(A1, $request),$request就是$this->passable。执行A1也就是执行function($request) use (B1, 'A'){}这块代码。具体是什么请看下面

// 这是getSlice()方法的一部分。上面已经注释过了所这里就每天家注释
function ($passable) use ($stack, $pipe) {
    if ($pipe instanceof Closure) {
        return call_user_func($pipe, $passable, $stack);
     } else {
         list($name, $parameters) = $this->parsePipeString($pipe);
         return call_user_func_array(
                    [$this->container->make($name), $this->method],
                    array_merge([$passable, $stack], $parameters)
                );
      }
};

接着A1的过程,判断A是不是匿名(回调)函数。明显不是,走下面。实例话中间件A并调用里面的handle方法。类似A->handle($request, $stack)。并且handle返回$stack($request);这就可以理解为B1($request),接着C1($request),接着$firstSlice($request)。不过要注意:$firstSlice($request)是什么?它不是洋葱皮而是核心。所以走自己的代码。$destination($request)->function($request){$this->app->instance('request', $request); return $this->router->dispatch($request);}结束。

这里是下面,直接调用$this->getSlice()返回什么?

// getSlice()的返回值,就是下面这段,可以直接把这段匿名函数代替调用getSlice()的地方。
function ($stack, $pipe){
    return function($request) use ($stack, $pipe)
    {
        //code...
    }
}

// 把这个匿名函数赋给一个变量,会变成什么样子?$callback()结果是什么?
$callback = function ($stack, $pipe){
    return function($request) use ($stack, $pipe)
    {
        //code...
    }
}

//$callback() -> 是下面函数的结果。
function($request) use ($stack, $pipe){//code...}
本作品采用《CC 协议》,转载必须注明作者和本文链接
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

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