slimphp中间件调用流程的理解
slimphp是一款微型php框架,主要是处理http请求,并调用合适的程序处理,并返回一个http响应。
它遵循php的psr7规范,可以很方便的集成其它遵循psr7规范的php组建。
当读到中间件时,官网给出了,如下所示的图
试验如下:
$mw1 = function ($request, $response, $next) { echo('middleware 1 start <br>'); $response = $next($request, $response); echo('middleware 1 end <br>'); return $response; }; $mw2 = function ($request, $response, $next) { echo('middleware 2 start <br>'); $response = $next($request, $response); echo('middleware 2 end <br>'); return $response; }; $app->get('/mw', function ($request, $response, $args) { echo(' Hello <br>'); return $response; })->add($mw1)->add($mw2);
输出为:
middleware 2 start
middleware 1 start
middleware 1 end
middleware 2 end
Hello
于是开始调试跟踪,发现原来如此:
在vendor\slim\slim\Slim\MiddlewareAwareTrait.php里有如下代码:
protected function addMiddleware(callable $callable) { if ($this->middlewareLock) { throw new RuntimeException('Middleware can’t be added once the stack is dequeuing'); } if (is_null($this->stack)) { $this->seedMiddlewareStack(); } $next = $this->stack->top(); $this->stack[] = function (ServerRequestInterface $req, ResponseInterface $res) use ($callable, $next) { $result = call_user_func($callable, $req, $res, $next); if ($result instanceof ResponseInterface === false) { throw new UnexpectedValueException( 'Middleware must return instance of \Psr\Http\Message\ResponseInterface' ); } return $result; }; return $this; }
$next 即参数为ServerRequestInterface $req, ResponseInterface $res的闭包,而$callable即我们的中间件。
中间件都添加到堆栈$this->stack[]上了,$next则是栈顶,而$this->seedMiddlewareStack();则把路由中间件第一个压栈了。
这就是官网调用顺序的流程了。
然而Hello 为何最后输出则还是费解,于是继续调试。
在vendor\slim\slim\Slim\Route.php里发现了痕迹:
__invoke函数中
if ($this->outputBuffering === false) { $newResponse = $handler($this->callable, $request, $response, $this->arguments); } else { try { ob_start(); $newResponse = $handler($this->callable, $request, $response, $this->arguments); $output = ob_get_clean(); } catch (Exception $e) { ob_end_clean(); throw $e; } }
关键是$output = ob_get_clean();
我们的echo输出被路由中间件拦截了,并放入了$response->getBody()->write($output);
if (!empty($output) && $response->getBody()->isWritable()) { if ($this->outputBuffering === 'prepend') { // prepend output buffer content $body = new Http\Body(fopen('php://temp', 'r+')); $body->write($output . $response->getBody()); $response = $response->withBody($body); } elseif ($this->outputBuffering === 'append') { // append output buffer content $response->getBody()->write($output); } }
在$response返回时才会输出,所以上面的Hello 是最后输出的。
那为啥$mw1、$mw2没有这个问题呢,因为我们的中间件就是直接输出,并不像路由中间件这么处理。
作者:半山
出处:http://www.cnblogs.com/xdao/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。