您的位置:首页 > 编程语言 > PHP开发

laravel5中对pipeline的理解

2015-12-21 15:01 627 查看
原文地址: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,我的理解就是arrayreduce中的第二个参数是一个closure,这个closure只接受两个参数的closure,而我们这里有一个$Passable变量需要不断传递,所以需要在内部再加一层function嵌套.

return function($stack, $pipe)
{
return function($passable) use ($stack, $pipe)
{
/**中间内容忽略
};
};
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: