PHP框架模式1:管道模式
计算机领域内管道模式其本质大体和现实领域的管道系统相同:栽荷从从抽象的管道的一端流入,经过一系列的处理,最终从管道的另一端流出。
管道模式的形式有很多种,常见的有:
- 进程间管道,通常用于兄弟进程、亲缘进程、父子进程及子进程之间的通讯;
- 凹型管道,用于客户端与服务端的业务流程处理及通讯;
- 直线型管道,用于客户端或服务端的一般流程性业务处理;
直线型的管道模式又可以分为自治型管道模式和约定型管道模式, 而绝大多数框架中提供的管道模式都是自治直线型管道,它通常被在同一个项目内结束的业务过程所使用,从而动态地组合碎片化的业务流程。。
自治型管道中的所有处理对象都是由自己添加,内部结构以及前后衔接都是由自己控制,以下示例参考Laravel的实现:
<?php
class Pipeline
{
/**
* 栽荷
*
* @var mixed
*/
protected $passable;
/**
* 管道
*
* @var array
*/
protected $pips = [];
/**
* 管道委托方法
*
* @var string
*/
protected $method = 'handle';
/**
* 设置管道要调用的方法
*
* @param string $method
* @return $this
*/
public function via(string $method)
{
$this->method = $method;
return $this;
}
/**
* 发送栽荷
*
* @param $passable
* @return $this
*/
public function send($passable)
{
$this->passable = $passable;
return $this;
}
/**
* 运行管道并执行回调
*
* @param Closure $destination
* @return mixed
*/
public function then(Closure $destination)
{
$pipeline = array_reduce(
array_reverse($this->pipes()), $this->carry(), $this->prepareDestination($destination)
);
return $pipeline($this->passable);
}
/**
* 运行回调并返回栽荷
*
* @return mixed
*/
public function thenReturn()
{
return $this->then(function ($passable) {
return $passable;
});
}
/**
* 设置管道数组
*
* @param $pipes
* @return $this
*/
public function through($pipes)
{
$this->pipes = is_array($pipes) ? $pipes : func_get_args();
return $this;
}
/**
* 管道委托调用
*
* @return Closure
*/
protected function carry()
{
return function ($stack, $pipe) {
return function ($passable) use ($stack, $pipe) {
if (is_callable($pipe)) {
// 管道可调用,例如方法,则直接调用
return $pipe($passable, $stack);
} else if (!is_object($pipe)) {
[$name, $parameters] = $this->parsePipeString($pipe);
$pipe = new $name();
$parameters = array_merge([$passable, $stack], $parameters);
} else {
$parameters = [$passable, $stack];
}
return method_exists($pipe, $this->method) ? $pipe->{$this->method}(...$parameters) : $pipe(...$parameters);
};
};
}
/**
* 从字符串获取类名和参数
*
* @param $pipe
* @return array
*/
protected function parsePipeString($pipe)
{
[$name, $parameters] = array_pad(explode(':', $pipe, 2), 2, []);
if (is_string($parameters)) {
$parameters = explode(',', $parameters);
}
return [$name, $parameters];
}
}
相比较传统的new pipeline()->pipe($callable)->pipe($obj)->process($passable)
这种链式调用,Laravel的实现非常的巧妙,它先反转了存储管道的数组,将最后加入管道封装为函数,作为上一个管道封装函数的参数, 直到最先加入的管道, 这样就形成了一条调用链, 而回调则作为array_reduce的第一个参数一直向下传递。
使用自治型管道模式
<?php
function filter1()
{
$passable[] = '采蘑菇的小姑娘';
return $passable;
}
class filter2
{
public function handle($passable, $message)
{
$passable[] = $message;
return $passable;
}
}
function callback($passable)
{
var_dump($passable);
}
$pipes = [
filter1(),
'filter2:爱吃鱼的大脸猫'
];
(new Pipeline())->send(['载荷'])->through($pipes)->then(callback());
自治直线型管道模式与责任链模式及过滤器模式的联系与区别
管道模式可以实现责任链和过滤器模式所实现的功能,但管道模式作为框架模式,它有更高的层级,所以管道模式通常用于与其他开发者之间的共识的约定, 例如Laravel的中间件。
发表回复