美文网首页程序员
PHP 中间件实现

PHP 中间件实现

作者: 睡觉吹灯 | 来源:发表于2020-08-08 15:07 被阅读0次

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

    一 、函数的传递

    在很多计算机编程语言中,函数可以作为参数传递到另外一个函数中。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)
    // }
    
    

    相关文章

      网友评论

        本文标题:PHP 中间件实现

        本文链接:https://www.haomeiwen.com/subject/siztdktx.html