一直在用Laravel
框架,很喜欢laravel
框架的中间件。在请求到结果之前,如果我们想要对路由或请求进行额外的处理,简单的加个Midleware
中间件就行了,很简单,很方便是不是。
最近几天看了下它的中间件的实现方式,把自己的心得感悟写下来分享给大家。
了解管道模式
laravel
的中间件用的是管道模式,我们先知道管道模式是什么:
所谓管道(Pipeline)设计模式就是将会数据传递到一个任务序列中,管道扮演者流水线的角色,数据在这里被处理然后传递到下一个步骤
管道,顾名思义,就是一个长长的流水管道,只不过加了许多阀门。所以管道模式大致需要三个角色:管道,阀门和载荷(流水)。如下图:
管道模式UML
模型图
开始代码之前,我们必须先了解管道模式的模型图
简单的实现
根据上面的模型图,我们来实现自己所理解的管道模式的代码:
/**
* PipelineBuilder 接口 即管道
* @method pipe 存入多个阀门
* @method process 输出
*/
interface PipelineBuilderInterface
{
public function __construct($payload);
public function pipe(StageBuilderInterface $stage);
public function process();
}
// 具体的管道类
class Pipeline implements PipelineBuilderInterface
{
protected $payload;
protected $pipes = [];
public function __construct($payload)
{
$this->payload = $payload;
}
public function pipe(StageBuilderInterface $stage)
{
$this->pipes[] = $stage;
return $this;
}
public function process()
{
foreach ($this->pipes as $pipe) {
call_user_func([$pipe, 'handle'], $this->payload);
}
}
}
// 阀门接口
interface StageBuilderInterface
{
public function handle($payload);
}
// 具体的阀门类
class StageOneBuilder implements StageBuilderInterface
{
public function handle($payload)
{
echo $payload .' 真是个';
}
}
// 具体的阀门类
class StageTwoBuilder implements StageBuilderInterface
{
public function handle($payload)
{
echo '帅气的男人';
}
}
// 输出:我真是个帅气的男人
$pipeline = new Pipeline('我');
$pipeline->pipe(new StageOneBuilder)
->pipe(new StageTwoBuilder)
->process();
底层源码
先来看看它的底层源码:
return (new Pipeline($this->container))
->send($request)
->through($middleware)
->then(function ($request) use ($route) {
return $this->prepareResponse(
$request, $route->run()
);
});
上面的代码是处理request
请求的一部分代码,send()
获取待处理的数据,through()
获取中间件,then()
传递闭包函数。
基本上,使用laravel pipelines
你可以将一个实例对象(object)在多个类之间传递,就像流水顺着管道依次流淌一般,最终呢,层层传递,你就得到了从头至尾一系列执行操作的“最终”结果。
模仿laravel pipeline
interface PipelineInterface
{
public function send($traveler);
public function through($stops);
public function via($method);
public function process();
}
interface StageInterface
{
public function handle($payload);
}
class StageOne implements StageInterface
{
public function handle($payload)
{
echo $payload . ' am really an ';
}
}
class StageTwo implements StageInterface
{
public function handle($payload) {
echo 'awesome man';
}
}
class Pipe implements PipelineInterface
{
protected $container;
protected $passable;
protected $pipes = [];
protected $via = 'handle';
public function __construct($container)
{
$this->container = $container;
}
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 via($method)
{
$this->via = $method;
return $this;
}
public function process()
{
foreach ($this->pipes as $pipe) {
// 返回处理后的结果
$this->passable = call_user_func([$pipe, $this->via], $this->passable);
}
}
}
$container = 'a';
$payload = 'wa';
$pipe = new Pipe($container);
// 输出:I am really an awesome man
$pipe->send($payload)->through([(new StageOne), (new StageTwo)])->process();
结语
上面的代码并没有达到laravel
中间件的真正执行部分,例子中只是用到了管道模式的一部分。像then()
方法中还用了array_reduce
和array_reverse
函数来处理请求,这一部分有时间会进一步研究。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。