Laravel框架的中间件使用:从请求进来到响应返回,经过中间件的层层包装,这种场景很适合用到一种设计模式---装饰器模式。
装饰器模式的作用,多种外界因素改变对象的行为。使用继承的方式改变行为不太被建议。
装饰器模式,即是有多个要改变对象的东西(装饰类),这些装饰类均实现一个接口。每个类在实现的接口中再调用构造器(或是setter等方法)传过来的其他装饰类对象的实现。
简单用一段代码描述下:
<?php interface Decorate {
function getInfo();
} /**
* Class DecoateA
* 初始化一个装饰对象
*/
class DecoateA implements Decorate{ /**
* 实现接口
*/
public function getInfo() {
echo __CLASS__;
}
} /**
* Class DecoateB
* 装饰DecoateA 的装饰类
*/
class DecoateB implements Decorate{ /**
* DecoateB constructor.
* @param Decorate $dec
* 构造器 传过来其他装饰类
*/
public function __construct(Decorate $dec) {
$this->dec = $dec;
} /**
* 实现接口
*/
public function getInfo() {
echo __CLASS__;
$this->dec->getInfo();
}
} $obj = new DecoateA();// 初始一个对象
$obj = new DecoateB($obj);// 装饰对象 $obj->getInfo();// DecoateBDecoateA
以上代码,可以简单理解装饰器模式。
再说Laravel的装饰器模式应用: (这里用静态方法模拟一下)
不像是上边的例子,把装饰类传过去,Laravel用到了大量的闭包Closure代替
一段代码
<?php interface Step
{
public static function go(Closure $next);
} /**
* Class FirstStep
* 装饰一
*/
class FirstStep implements Step
{
public static function go(Closure $next)
{
echo __CLASS__." start<br/>";
$next();
echo __CLASS__." end<br/>";
}
} /**
* Class SecondStep
* 装饰二
*/
class SecondStep implements Step
{
public static function go(Closure $next)
{
echo __CLASS__." start<br/>";
$next();
echo __CLASS__." end<br/>";
}
} function goFun($step, $className)
{
return function () use ($step, $className)
{
return $className::go($step);
};
} function then()
{
$step = ['FirstStep', 'SecondStep'];
$prepare = function () {
echo "_init_"."<br/>";
};
call_user_func(array_reduce($step, "goFun", $prepare));
} then(); /**
SecondStep start
FirstStep start
_init_
FirstStep end
SecondStep end
**/
这里需要理解下 array_reduct()的用法,第一个参数是被循环的数组,第二个是回调函数(其中回调函数的第一个参数是每次该函数上一次的return值,否则是array_reduce的第三个参数的初始值),第三个参数是初始值。
对于then() 的内部实现,可能开始理解比较困难。可以分拆一下实现:如下代码
// 初始闭包
$initFun = function (){
echo "_init_"."<br/>";
}; // 相当于array_reduce 第一次执行
$obj = function () use ($initFun) {
return FirstStep::go($initFun);
}; // 相当于array_reduce 第二次执行。go传递的都是个闭包函数
SecondStep::go($obj);