• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

装饰器模式在Laravel中的应用

php 搞代码 3年前 (2022-02-28) 52次浏览 已收录 0个评论
文章目录[隐藏]

什么是装璜器模式

装璜器模式容许向一个现有的对象增加新的性能,同时又不扭转其构造。

简略代码实现:

<code class="php">interface Decorate {
    function getInfo();
}

/**
 * Class DecoateA
 * 初始化一个装璜对象
 */
class DecoateA implements Decorate{

    /**
     * 实现接口
     */
    public function getInfo() {
        echo __CLASS__.PHP_EOL;
    }
}

/**
 * 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__.PHP_EOL;
        $this->dec->getInfo();
    }
}


// 通过一直的创立装璜对象来增加性能
$obj = new DecoateA();// 初始一个对象
$obj = new DecoateB($obj);// 装璜对象

$obj->getInfo();
// DecoateB
// DecoateA

装璜器和Laravel中间件

装璜器对现有对象一直增加性能的思维,与框架中间件的思维统一,框架中间件就是对装璜器模式的一大利用。

一个申请能够视为现有对象,在申请达到控制器之前,须要通过 Laravel 框架的各种中间件,每个中间件都对申请进行不同的“装璜”,当申请达到控制器执行结束进行响应客户端,一个响应返回途中要通过刚刚来时的通过的中间件,每个中间件都能够对响应进行不同的“装璜”,最初响应达到客户端。这个流程是一个典型的“洋葱模型”。

以一个简短的代码表白 Laravel 中间件原理

<code class="php">interface Middleware
{
    public static function handle(Closure $next);
}

/**
 * 中间件A(能够视为装璜类A)
 */
class MiddlewareA implements Middleware
{
    public static function handle(Closure $next)
    {
        echo __CLASS__." start".PHP_EOL;
        $next();
        echo __CLASS__." end".PHP_EOL;
    }
}

/**
 * 中间件B(能够视为装璜类B)
 */
class MiddlewareB implements Middleware
{
    public static function handle(Closure $next)
    {
        echo __CLASS__." start".PHP_EOL;
        $next();
        echo __CLASS__." end".PHP_EOL;
    }
}

/**
 * 生成闭包函数
 */
function makeClosureFun($carry, $middlerwareClass)
{
    return function () use ($carry, $middlerwareClass) {
        return $middlerwareClass::handle($carry);
    };
}

/**
 * 执行
 */

// Kernel 中的中间件数组
$middlerwareArray = [
    'MiddlewareA',
    'MiddlewareB'
];

$prepare = function () {
    echo "_init_".PHP_EOL;
};

// 组装闭包
$closure = array_reduce($middlerwareArray, 'makeClosureFun', $prepare);
// 执行
call_user_func($closure);

后果:

MiddlewareB start
MiddlewareA start
_init_
MiddlewareA end
MiddlewareB end

以上代码输入的后果,正好合乎中间件的“洋葱模型”。

代码解析

这是如何是实现的呢?实现中间件的要害是 array_reduce() + 闭包函数。

array_reduce() 第一个参数是数组,第二个参数是回调函数,第三个参数是解决开始或完结时触发的函数。

array_reduce 会给回调函数传入两个参数,carry 和 item ,别离是上次迭代返回的值和本次迭代的值。

组装闭包

当组装闭包时,部分代码如下

<code class="php">function makeClosureFun($carry, $middlerwareClass)
{
    return function () use ($carry, $middlerwareClass) {
        // 疏忽视为黑盒
    };
}

// 组装闭包
$closure = array_reduce($middlerwareArray, 'makeClosureFun', $prepare);

makeClosureFun() 返回了一个 use 两个变量的闭包函数,至于这个闭包函数外部具体做了什么不必关注,将其视为一个黑盒。闭包函数 use 的 这两个参数别离是 array_reduce() 传给闭包的上次迭代返回的值和本次要迭代的值。

当第一次迭代执行 makeClosureFun() 时,返回了一个闭包函数,这个闭包函数存储时实际上时一个闭包类,能够看到 use 的两个参数存到 static 属性下。

<code class="php">object(Closure)#2 (1) {
    ["static"]=>
    array(2) {
    ["carry"]=>
    object(Closure)#1 (0) {
    }
    ["middlerwareClass"]=>
    string(11) "MiddlewareA"
    }
}

第一个迭代返回的闭包函数,持续作为了第二次迭代的 $carry 传入, $middlerwareClass 变为了 $middlerwareArray 数组的第二个元素。如此迭代,到最初失去的 $closure

object(Closure)#3 (1) {
  ["static"]=>
  array(2) {
    ["carry"]=>
    object(Closure)#2 (1) {
      ["static"]=>
      array(2) {
        ["carry"]=>
        object(Closure)#1 (0) {
        }
        ["middlerwareClass"]=>
        string(11) "MiddlewareA"
      }
    }
    ["middlerwareClass"]=>
    string(11) "MiddlewareB"
  }
}

执行闭包

应用 call_user_func() 执行 $closure 变量中的闭包函数。

TODO: PHP 如何依据闭包变量中的构造找到对应函数代码片段?(OR call_user_func如何执行闭包函数?)

第一次执行 use 引入 $carry$middlerwareClass, 执行 $middlerwareClass::handle($carry),此时 $middlerwareClass 值为 MiddlewareB,即执行 MiddlewareB::handle($carry) ,传入的 $carry 值是一个闭包。MiddlewareB类中 handle() 办法在先执行 MiddlewareB start 输入,通过 $next() 执行闭包,即第二次执行。

这次执行 $middlerwareClass::handle($carry),此时 $middlerwareClass 值为 MiddlewareA,即执行 MiddlewareA::handle($carry),输入 MiddlewareA start , 执行闭包 $next(),PHP发现闭包为空,触发 array_reduce() 给设定的 $prepare 闭包,输入 _init_,随后开始回头,输入 MiddlewareA end,再输入MiddlewareB end

参考文章

次要参考,特地鸣谢此文作者

装璜器模式以及Laravel框架下的中间件利用

延长浏览

Pipeline 管道操作实现申请中间件过滤(最具体解说)


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:装饰器模式在Laravel中的应用

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址