本文采用层层递进的方式描述了中间件的实现,众看官且看。
一 、函数的传递
在很多计算机编程语言中,函数可以作为参数传递到另外一个函数中。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)
// }