PHP 中间件实现

本文采用层层递进的方式描述了中间件的实现,众看官且看。

一 、函数的传递

在很多计算机编程语言中,函数可以作为参数传递到另外一个函数中。PHP 的例子如下

$fun = function () {
    echo 'This is A fun' . PHP_EOL;
};

function main($fun) {
    $fun();
}

main($fun);

// 执行结果:
// This is A fun

二、装饰器函数

假设在执行主函数的时候,在主函数前后都需要执行一段代码,这时我们可以不直接调用主函数,而是使用另外的函数来装饰主函数:

$wrapper = function ($fun) {
    echo 'Before main' . PHP_EOL;
    $fun();
    echo 'After main' . PHP_EOL;
};

$main = function () {
    echo 'Main' . PHP_EOL;
};

// 带有装饰器的主函数
$next = function () use ($wrapper, $main) {
    $wrapper($main);
};

$next();

// 执行结果:
// Before main
// Main
// After main

 
假设有多个装饰器函数,就需要一层一层往里边传递:

// 装饰器 A
$wrapperA = function ($next) {
    echo 'Before A' . PHP_EOL;
    $next();
    echo 'After A' . PHP_EOL;
};

// 装饰器 B
$wrapperB = function ($next) {
    echo 'Before B' . PHP_EOL;
    $next();
    echo 'After B' . PHP_EOL;
};

$main = function () {
    echo 'Main' . PHP_EOL;
};

$next = $main;

$next = function () use ($wrapperA, $next) {
    $wrapperA($next);
};

$next = function () use ($wrapperB, $next) {
    $wrapperB($next);
};

$next();

// 执行结果:
// Before B
// Before A
// Main
// After A
// After B

 
再前进一步,将层层传递的部分写成一个 foreach 循环。这样,如果有10个装饰器就能节约很多代码:

// 装饰器 A
$wrapperA = function ($next) {
    echo 'Before A' . PHP_EOL;
    $next();
    echo 'After A' . PHP_EOL;
};

// 装饰器 B
$wrapperB = function ($next) {
    echo 'Before B' . PHP_EOL;
    $next();
    echo 'After B' . PHP_EOL;
};

$main = function () {
    echo 'Main' . PHP_EOL;
};

$next = $main;

$wrapper_list = [$wrapperA, $wrapperB];

foreach ($wrapper_list as $wrapper) {
    $next = function () use ($wrapper, $next) {
        $wrapper($next);
    };
}

$next();

// 执行结果:
// Before B
// Before A
// Main
// After A
// After B

三、中间件

最后,献上一段我按照自己的理解写的中间件代码,仅供参考。相信理解了前面的代码,这部分就变得很容易了。

class Request
{
    public $num = 10;
}

class Response
{
    public $code = -10;
}

interface MiddleWareInterface
{
    /**
     * @param Request $request
     * @param $closure
     * @return Response
     */
    public function execute(Request $request, $closure);
}

class MiddleWareA implements MiddleWareInterface
{
    /**
     * @param Request $request
     * @param $closure
     * @return Response
     */
    public function execute(Request $request, $closure)
    {
        $request->num ++;
        $response = $closure($request);
        $response->code --;
        return $response;
    }
}

class MiddleWareB implements MiddleWareInterface
{
    /**
     * @param Request $request
     * @param $closure
     * @return Response
     */
    public function execute(Request $request, $closure)
    {
        $request->num ++;
        $response = $closure($request);
        $response->code --;
        return $response;
    }
}


function get_global_middleware()
{
    return [
        MiddleWareA::class,
        MiddleWareB::class,
    ];
}

class App
{

    public function run($request)
    {
        $global_middle_ware = get_global_middleware();
        
        $next = function () use ($request) {
            return $this->do($request);
        };

        foreach ($global_middle_ware as $middleware) {
            $m = new $middleware;

            $next = function () use ($request, $middleware, $next, $m) {
                return $m->execute($request, $next) ;
            };

        }

        $response = $next();
        return $response;
    }

    public function do($request)
    {
        $response = new Response();
        return $response;
    }

}

$app = new App();
$request = new Request();
$response = $app->run($request);

var_dump($request);
var_dump($response);

// 执行结果
// object(Request)#2 (1) {
// ["num"]=>
//   int(12)
// }
// object(Response)#8 (1) {
// ["code"]=>
//   int(-12)
// }

猜你喜欢

转载自blog.csdn.net/weixin_40369062/article/details/107932863