laravel5中对pipeline的理解

原文地址:laravel5中对pipeline的理解 http://sheefeng.com/laravel5-pipeline/


pipeline在laravel中的应用

Router和ControllerDispatcher中都用到了pipeline结构,具体如下所示:
router中的Pipeline:

/**
 * Run the given route within a Stack "onion" instance.
 *
 * @param  \Illuminate\Routing\Route  $route
 * @param  \Illuminate\Http\Request  $request
 * @return mixed
 */
protected function runRouteWithinStack(Route $route, Request $request)
{
    $middleware = $this->gatherRouteMiddlewares($route);

    return (new Pipeline($this->container))
                    ->send($request)
                    ->through($middleware)
                    ->then(function($request) use ($route)
                    {
                        return $this->prepareResponse(
                            $request,
                            $route->run($request)
                        );
                    });
}

ControllerDispatcher中的Pipeline:

/**
 * Call the given controller instance method.
 *
 * @param  \Illuminate\Routing\Controller  $instance
 * @param  \Illuminate\Routing\Route  $route
 * @param  \Illuminate\Http\Request  $request
 * @param  string  $method
 * @return mixed
 */
protected function callWithinStack($instance, $route, $request, $method)
{
    $middleware = $this->getMiddleware($instance, $method);

    // Here we will make a stack onion instance to execute this request in, which gives
    // us the ability to define middlewares on controllers. We will return the given
    // response back out so that "after" filters can be run after the middlewares.
    return (new Pipeline($this->container))
                ->send($request)
                ->through($middleware)
                ->then(function($request) use ($instance, $route, $method)
                {
                    return $this->call($instance, $route, $method);
                });
}

pipeline的存在主要是为了处理中间件逻辑.
router中的pipeline主要是首先运行选定某一个match到的route后,执行这个route所对应的的MiddleWare,最后执行这个route所对应的controller操作(在controller操作中,也会涉及到pipeline应用,如下).
ControllerDispatcher中的pipeline主要是运行Controller层面(已经选定了某个route以后)的MiddleWare,然后再最后执行controller中的具体操作($this->call($instance, $route, $method)).

理解pipeline,就要理解洋葱模型,像剥洋葱一样一层一层往里面剥.以下面语句为例:

(new Pipeline($this->container))
                ->send($passable)
                ->through($middleware)
                ->then($destination);

将容器$this->container注入pipeline,$passable这个变量一直在被传递,middleware数组代表要穿过的层,$destination一般是一个闭包函数,代表最终要执行的动作.

上述语句的含义就是携带着$passable这个变量,穿越层层MiddleWare,然后执行最后的$destination,如下所示:

pipeline的基本原理

下面再来看看pipeline的基本原理:

先看看pipeline的源码:

<?php namespace Illuminate\Pipeline;

use Closure;
use Illuminate\Contracts\Container\Container;
use Illuminate\Contracts\Pipeline\Pipeline as PipelineContract;

class Pipeline implements PipelineContract {

/**
 * The container implementation.
 *
 * @var \Illuminate\Contracts\Container\Container
 */
protected $container;

/**
 * The object being passed through the pipeline.
 *
 * @var mixed
 */
protected $passable;
  //要在洋葱模型中传递的变量,可以是一个Request对象

/**
 * The array of class pipes.
 *
 * @var array
 */
protected $pipes = array();
   //在洋葱模型中要经过的管道,一般是一些MiddleWare

/**
 * The method to call on each pipe.
 *
 * @var string
 */
protected $method = 'handle';

/**
 * Create a new class instance.
 *
 * @param  \Illuminate\Contracts\Container\Container  $container
 * @return void
 */
public function __construct(Container $container)
{
    $this->container = $container;
}

/**
 * Set the object being sent through the pipeline.
 *
 * @param  mixed  $passable
 * @return $this
 */
public function send($passable)
{
    $this->passable = $passable;

    return $this;
}

/**
 * Set the array of pipes.
 *
 * @param  dynamic|array  $pipes
 * @return $this
 */
public function through($pipes)
{
    $this->pipes = is_array($pipes) ? $pipes : func_get_args();

    return $this;
}

/**
 * Set the method to call on the pipes.
 *
 * @param  string  $method
 * @return $this
 */
public function via($method)
{
    $this->method = $method;

    return $this;
}

/**
 * Run the pipeline with a final destination callback.
 *
 * @param  \Closure  $destination
 * @return mixed
 */
public function then(Closure $destination)
{
    $firstSlice = $this->getInitialSlice($destination);
    //将passable变量和destination这个闭包结合起来,生成一个新的闭包为firstSlice

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

    return call_user_func(
        array_reduce($pipes, $this->getSlice(), $firstSlice), $this->passable
    );
         //核心步骤
}

/**
 * Get a Closure that represents a slice of the application onion.
 *
 * @return \Closure
 */
protected function getSlice()
{
    return function($stack, $pipe)
    {
        return function($passable) use ($stack, $pipe)
        {
            // If the pipe is an instance of a Closure, we will just call it directly but
            // otherwise we'll resolve the pipes out of the container and call it with
            // the appropriate method and arguments, returning the results back out.
            if ($pipe instanceof Closure)
            {
                return call_user_func($pipe, $passable, $stack);
            }
            else
            {
                return $this->container->make($pipe)
                        ->{$this->method}($passable, $stack);
            }
        };
    };
}

/**
 * Get the initial slice to begin the stack call.
 *
 * @param  \Closure  $destination
 * @return \Closure
 */
   //getInitialSlice()用来生成一个closure来实现$destination中的动作.
protected function getInitialSlice(Closure $destination)
{
    return function($passable) use ($destination)
    {
        return call_user_func($destination, $passable);
    };
}

}

上面的

return call_user_func(
        array_reduce($pipes, $this->getSlice(), $firstSlice), $this->passable
    );

是核心步骤,不了解arrayreduce语法的人可以参考:http://php.net/manual/zh/function.array-reduce.php

getInitialSlice()用来生成一个closure来实现$destination中的动作.


getSlice()方法用来构造一个closure来不断的迭代pipes里面的每一个pipe
至于getSlice()方法中为何会向下面这样嵌套两个function,我的理解就是array
reduce中的第二个参数是一个closure,这个closure只接受两个参数的closure,而我们这里有一个$Passable变量需要不断传递,所以需要在内部再加一层function嵌套.

return function($stack, $pipe)
     {
        return function($passable) use ($stack, $pipe)
        {
            /**中间内容忽略
        };
    };
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值