PHP进阶5 装饰者模式在Laravel中中间件的应用

                    不积跬步无以至千里不积小流无以成江海


装饰者模式是在开放-关闭原则下实现动态添加或者减少功能的一种方式,类似于洋葱,分很多层,每一层都有一定的功能,可以随时添加和修改这些层,官方将这些层称之为中间件Middleware。

前置知识

1、mixed array_reduce ( array $array , callable $callback [, mixed $initial = NULL ] )
    array_reduce() 将回调函数 callback 迭代地作用到 array 数组中的每一个单元中,从而将数组简化为单一的值
        array   输入的 array
        mixed callback ( mixed $carry , mixed $item )
            carry    携带上次迭代里的值; 如果本次迭代是第一次,那么这个值是 initial。
            item     携带了本次迭代的值。
        initial   如果指定了可选参数 initial,该参数将在处理开始前使用,或者当处理结束,数组为空时的最后一个结果。
$a = [1, 2, 3, 4, 5];

function sum($carry, $item)
{
    $carry += $item;
    echo $carry . '<br>';     //  1 3 6 10 15
    return $carry;
}

var_dump(array_reduce($a, 'sum'));  //  int(15)

function product($carry, $item)
{
    $carry *= $item;
    echo $carry . '<br>';   //  10 20 60 240 1200
    return $carry;
}

var_dump(array_reduce($a, 'product',10));   //  int(1200)

$x = [];

var_dump(array_reduce($x, "sum", "No data to reduce"));

2、call_user_func

    把第一个参数作为回调函数调用 mixed call_user_func ( callable $callback [, mixed $parameter [, mixed $... ]] ) 第一个参数 callback 是被调用的回调函数,其余参数是回调函数的参数

3、装饰者模式

<?php

interface Decorator
{
    public function display();
}

class XiaoFang implements Decorator
{

    private $name;

    public function __construct($name)
    {
        $this->name = $name;
    }

    public function display()
    {
        echo "我是" . $this->name . "我出门了!!!" . '<br>';
    }

}

class Finery implements Decorator
{

    private $component;

    public function __construct(Decorator $compent)
    {
        $this->component = $compent;
    }

    public function display()
    {
        $this->component->display();
    }
}

class Shoes extends Finery
{

    public function display()
    {
        echo '穿上鞋子' . '<br>';
        parent::display();
    }
}

class Skirt extends Finery
{

    public function display()
    {
        echo "穿上裙子" . '<br>';
        parent::display();
    }
}

class Fire extends Finery
{

    public function display()
    {
        echo '出门前先整理头发' . '<br>';
        parent::display();
        echo '出门后再整理一下头发' . '<br>';
    }
}

$xiaofang = new XiaoFang('小芳');
$shoes = new Shoes($xiaofang);
$skirt = new Skirt($shoes);
$fire = new Fire($skirt);
$fire->display();

/**
 * 1、出门前先整理头发
 * 2、调用$skirt的diaplay()方法:穿上裙子
 * 3、调用$shoes的display()方法:穿上鞋子
 * 4、调用$xiaofang的diaplay()方法:我是小芳,我出门了
 * 5、出门后再整理一下头发
 */

简化版的中间件启动顺序

<?php

interface Step
{
    public static function go(Closure $next);
}

class FirstStep implements Step
{
    public static function go(Closure $next)
    {
        echo "开启session,获取数据" . '<br>';
        $next();
        echo "保存数据,关闭session" . '<br>';
    }
}

function goFun($step, $className)
{
    return function () use ($step, $className) {
        return $className::go($step);
    };
}

function then()
{
    $steps = ["FirstStep"];

    $prepare = function () {
        echo "请求向路由器传递,返回响应" . '<br>';
    };

    /**
     * 第一个参数是要处理的数组
     * 第二个参数是处理函数名称或回调函数
     * 第三个参数为可选参数,为初始化参数,将被当作数组中的第一个值来处理,如果数组为空则作为返回值
     * 这里第三个参数传递一个回调函数,该函数用于将请求向路由器继续传递,返回响应
     * 第一个参数为数组,该数组记录了外层功能的类名
     * goFun函数作为处理数组的回调函数
     * array_reduce()最终返回的是一个回调函数,即$go
     * $go = function() {
     *     return $FirstStep::go(function() {
     *         echo "请求向路由器传递,返回响应" . '<br>';
     * });
     * }
     */
    $go = array_reduce($steps, "goFun", $prepare);

    $go();
}

then();

升级版的中间件依次执行顺序

<?php

interface Middleware
{
    public static function handle(Closure $next);
}

class VerifyCsrfToken implements Middleware
{
    public static function handle(Closure $next)
    {
        echo "验证Csrf-Token" . '<br>';
        $next();
    }
}

class ShareErrorsFromSession implements Middleware
{
    public static function handle(Closure $next)
    {
        echo "如果session中有'error'变量,则共享他" . '<br>';
        $next();
    }
}

class StartSession implements Middleware
{
    public static function handle(Closure $next)
    {
        echo "开启session" . '<br>';
        $next();
        echo "保存数据,关闭session" . '<br>';
    }
}

class AddQueuedCookieToResponse implements Middleware
{
    public static function handle(Closure $next)
    {
        $next();
        echo "添加下一次请求需要的cookie" . '<br>';
    }
}

class EncryptCookie implements Middleware
{
    public static function handle(Closure $next)
    {
        echo "对输入请求的cookie进行解密" . '<br>';
        $next();
        echo "对输出响应的cookie进行加密" . '<br>';
    }
}

class CheckFormaintenanceMode implements Middleware
{
    public static function handle(Closure $next)
    {
        echo "确定当前程序是否处于维护状态" . '<br>';
        $next();
    }
}

function getSlice()
{
    return function ($stack, $pipe) {
        return function () use ($stack, $pipe) {
            return $pipe::handle($stack);
        };
    };
}

function then()
{
    $pipes = [
        "CheckFormaintenanceMode",
        "EncryptCookie",
        "AddQueuedCookieToResponse",
        "StartSession",
        "ShareErrorsFromSession",
        "VerifyCsrfToken"
    ];

    $firstSlice = function () {
        echo "请求向路由器传递,返回响应" . "<br>";
    };

    $pipes = array_reverse($pipes);

    call_user_func(
        array_reduce($pipes, getSlice(), $firstSlice)
    );
}

then();

VerifyCsrfToken::handle(
    function () {
        echo "请求向路由器传递,返回响应" . "<br>";
    }
);

/**************************逻辑分析*****************************

ShareErrorsFromSession::handle(
    VerifyCsrfToken::handle(
        function () {
            echo "请求向路由器传递,返回响应" . "<br>";
        }
    )
);

StartSession::handle(
    ShareErrorsFromSession::handle(
        VerifyCsrfToken::handle(
            function () {
                echo "请求向路由器传递,返回响应" . "<br>";
            }
        )
    )
);
AddQueuedCookieToResponse::handle(
    StartSession::handle(
        ShareErrorsFromSession::handle(
            VerifyCsrfToken::handle(
                function () {
                    echo "请求向路由器传递,返回响应" . "<br>";
                }
            )
        )
    )
);
EncryptCookie::handle(
    AddQueuedCookieToResponse::handle(
        StartSession::handle(
            ShareErrorsFromSession::handle(
                VerifyCsrfToken::handle(
                    function () {
                        echo "请求向路由器传递,返回响应" . "<br>";
                    }
                )
            )
        )
    )
);

CheckFormaintenanceMode::handle(    //  确定当前程序是否处于维护状态
    EncryptCookie::handle(          //  对输入请求的cookie进行解密
        AddQueuedCookieToResponse::handle(
            StartSession::handle(   //  开启session,获取数据
                ShareErrorsFromSession::handle( //  如果session中有error变量,则共享他
                    VerifyCsrfToken::handle(    //  验证csrf-token
                        function () {
                            echo "请求向路由器传递,返回响应" . "<br>";  //  请求向路由器传递,返回响应
                        }
                    )
                )
            )   //  保存数据,关闭session
        )   //  添加下一次请求需要的cookie
    )
    //  对输出响应的cookie进行解密
);

 * ****************************************************************/


猜你喜欢

转载自blog.csdn.net/Dote2r/article/details/81154664
今日推荐