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没有这个问题呢,因为我们的中间件就是直接输出,并不像路由中间件这么处理。
slimphp中间件调用流程的理解的更多相关文章
- Android深入源代码分析理解Aidl总体调用流程(雷惊风)
2017年開始上班的第一天.老不想工作了,假期感觉还没開始就已经结束了,唉,时间就是这样,新的一年開始了,尽管非常不想干正事,没办法,必须干起来.由于后边的路还非常长,距离六十岁还非常远. 刚上班也没 ...
- android从应用到驱动之—camera(1)---程序调用流程
一.开篇 写博客还得写开篇介绍,可惜,这个不是我所擅长的.就按我自己的想法写吧. 话说camera模块,从上层到底层一共包含着这么几个部分: 1.apk------java语言 2.camera的ja ...
- android从应用到驱动之—camera(1)---程序调用流程[转]
一.开篇 写博客还得写开篇介绍,可惜,这个不是我所擅长的.就按我自己的想法写吧. 话说camera模块,从上层到底层一共包含着这么几个部分: 1.apk------java语言 2.camera的ja ...
- RxJava && Agera 从源码简要分析基本调用流程(1)
版权声明:本文由晋中望原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/123 来源:腾云阁 https://www.qclo ...
- (转)android从应用到驱动之—camera(1)---程序调用流程
一.开篇 写博客还得写开篇介绍,可惜,这个不是我所擅长的.就按我自己的想法写吧. 话说camera模块,从上层到底层一共包含着这么几个部分: 1.apk------java语言 2.camera的ja ...
- OkHttp完全解析之整体调用流程
前言:阅读好的代码如同观赏美景一样的美妙 OkHttp是一个Square公司在github开源的Java网络请求框架,非常流行.OkHttp 的代码并不是特别庞大,代码很多巧妙的实现,非常值得学习. ...
- 学完微型服务器(Tomcat)对其工作流程的理解,自己着手写个简单的tomcat
学完微型服务器(Tomcat)对其工作流程的理解,自己着手写个简单的tomcat 2019-05-09 19:28:42 注:项目(MyEclipse)创建的时候选择:Web Service Pr ...
- 微信授权流程和JSSDK调用流程
概念理解 业务域名:当前业务使用的是哪个网站,好处:设置业务域名后,在微信内访问该域名下页面时,不会被重新排版.不出现“防欺诈盗号,请误支付或输入qq密码”的提示,微信认为该域名是安全的,客户也不觉得 ...
- .net core 源码解析-mvc route的注册,激活,调用流程(三)
.net core mvc route的注册,激活,调用流程 mvc的入口是route,当前请求的url匹配到合适的route之后,mvc根据route所指定的controller和action激活c ...
随机推荐
- VC++程序员如何做好界面
本屌丝在新春放假期间闲来无事,在各大编程论坛溜达了一圈.发现年前的帖子中,有VC++程序员在界面开发方面遇到了很多苦恼,有抱怨界面工作不好做的,有抱怨用错了界面库的,也有紧急求得技术问题帮助的.看到这 ...
- iOS支付宝支付集成
概述 iOS支付宝支付集成 详细 代码下载:http://www.demodashi.com/demo/10729.html 支付宝和微信都是业界的老大哥,相信大家都有所觉得文档.SDK都是各种坑吧( ...
- genymotion安装(unknown generic error)及配置在Android studio环境中
/*转载请注明出处.本文地址:http://write.blog.csdn.net/postedit/44261371*/ genymotion模拟器的长处我就不阐述了,一个字:快!! .如今来说一下 ...
- HDUOJ---大菲波数
大菲波数 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submis ...
- 【LeetCode】88. Merge Sorted Array (2 solutions)
Merge Sorted Array Given two sorted integer arrays A and B, merge B into A as one sorted array. Note ...
- XP和Win 7双系统安装说明和注意事项
安装前说明: 1.先装XP,再装Windows 7,最好不要反过来,不然XP不会把Windows 7的启动管理器给覆盖掉,会麻烦些.总之遵循“旧版本到新版本”安装原则. 2.如果分区不够大,请用以下软 ...
- SQL SERVER 2005允许自定义聚合函数-表中字符串分组连接
不多说了,说明后面是完整的代码,用来将字符串型的字段的各行的值拼成一个大字符串,也就是通常所说的Concat 例如有如下表dict ID NAME CATEGORY 1 RED COLOR ...
- 通过UNIX域套接字传递描述符和 sendmsg/recvmsg 函数
在前面我们介绍了UNIX域套接字编程,更重要的一点是UNIX域套接字可以在同一台主机上各进程之间传递文件描述符. 下面先来看两个函数: #include <sys/types.h> #i ...
- Python 列表 remove() 方法
描述 Python 列表 remove() 方法通过指定元素的值来移除列表中某个元素的第一个匹配项,如果这个元素不在列表中会报一个异常. 语法 remove() 方法语法: L.remove(obj) ...
- tomcat多域名配置(转)
TOMCAT的域名配置 现在很多的公司的网站都是用tomcat作为应用服务区的,可是对于初学者,8080端口号是如何去掉的,这些网站是如何和域名绑定到一起的呢?一个 tomcat是如何绑定多域名?并且 ...