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

 
不难看出实际是
1、调用$mw2 输出 middleware 2 start  
2、调用$mw2里的$next即$mw1 输出middleware 1 start 
3、$mw1再调用$next,而此时没有中间件了,直接输出了middleware 1 end  
4、由于$mw2还没return,还在调用栈里,接着输出middleware 2 end
5、对于这个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中间件调用流程的理解的更多相关文章

  1. Android深入源代码分析理解Aidl总体调用流程(雷惊风)

    2017年開始上班的第一天.老不想工作了,假期感觉还没開始就已经结束了,唉,时间就是这样,新的一年開始了,尽管非常不想干正事,没办法,必须干起来.由于后边的路还非常长,距离六十岁还非常远. 刚上班也没 ...

  2. android从应用到驱动之—camera(1)---程序调用流程

    一.开篇 写博客还得写开篇介绍,可惜,这个不是我所擅长的.就按我自己的想法写吧. 话说camera模块,从上层到底层一共包含着这么几个部分: 1.apk------java语言 2.camera的ja ...

  3. android从应用到驱动之—camera(1)---程序调用流程[转]

    一.开篇 写博客还得写开篇介绍,可惜,这个不是我所擅长的.就按我自己的想法写吧. 话说camera模块,从上层到底层一共包含着这么几个部分: 1.apk------java语言 2.camera的ja ...

  4. RxJava && Agera 从源码简要分析基本调用流程(1)

    版权声明:本文由晋中望原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/123 来源:腾云阁 https://www.qclo ...

  5. (转)android从应用到驱动之—camera(1)---程序调用流程

    一.开篇 写博客还得写开篇介绍,可惜,这个不是我所擅长的.就按我自己的想法写吧. 话说camera模块,从上层到底层一共包含着这么几个部分: 1.apk------java语言 2.camera的ja ...

  6. OkHttp完全解析之整体调用流程

    前言:阅读好的代码如同观赏美景一样的美妙 OkHttp是一个Square公司在github开源的Java网络请求框架,非常流行.OkHttp 的代码并不是特别庞大,代码很多巧妙的实现,非常值得学习. ...

  7. 学完微型服务器(Tomcat)对其工作流程的理解,自己着手写个简单的tomcat

    学完微型服务器(Tomcat)对其工作流程的理解,自己着手写个简单的tomcat 2019-05-09   19:28:42 注:项目(MyEclipse)创建的时候选择:Web Service Pr ...

  8. 微信授权流程和JSSDK调用流程

    概念理解 业务域名:当前业务使用的是哪个网站,好处:设置业务域名后,在微信内访问该域名下页面时,不会被重新排版.不出现“防欺诈盗号,请误支付或输入qq密码”的提示,微信认为该域名是安全的,客户也不觉得 ...

  9. .net core 源码解析-mvc route的注册,激活,调用流程(三)

    .net core mvc route的注册,激活,调用流程 mvc的入口是route,当前请求的url匹配到合适的route之后,mvc根据route所指定的controller和action激活c ...

随机推荐

  1. 金山PDF

    金山是个很不错的软件公司,金山出PDF,纯粹是完善生态圈!毕竟没FoxitReader专业对PDF的处理上! 官网:芝麻开门 下载:http://wdl1.cache.wps.cn/wps/downl ...

  2. mysql中的order by

    一.order by的原理 1.利用索引的有序性获取有序数据 当查询语句的 order BY 条件和查询的执行计划中所利用的 Index 的索引键(或前面几个索引键)完全一致,且索引访问方式为 ran ...

  3. HDUOJ-----4506小明系列故事——师兄帮帮忙

    小明系列故事——师兄帮帮忙 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Tot ...

  4. Block编程注意的问题

    一,前言   block 是在 iOS 4 中引入的新特性,它和 C++ 11 中的 lamba 表达式概念相似,有时候也被称为闭包.经过一段时间的使用,我发现要用对用好 block 还是有不少需要注 ...

  5. UE 技巧

    http://cache.baiducontent.com/c?m=9d78d513d98416b8599d830e7c01a7170e2585744ddcc4523f8a9c12d522195646 ...

  6. oc引入头文件

    建立.h的头文件(header file)命名为Hi.h,源码如下: #ifndef oc3_Hi_h #define oc3_Hi_h void sayHi(); #endif 建立.c的头文件(c ...

  7. OAF_OAF Framework学习笔记的基本概念(概念)

    2014-11-02 Created By BaoXinjian

  8. Linux内存初始化(四) 创建系统内存地址映射

    一.前言 经过内存初始化代码分析(一)和内存初始化代码分析(二)的过渡,我们终于来到了内存初始化的核心部分:paging_init.当然本文不能全部解析完该函数(那需要的篇幅太长了),我们只关注创建系 ...

  9. WIN7下恼人的AppData——删除没用的缓存文件

    今日.打开电脑,发现C盘可用容量居然变得非常小.认为非常是可疑,例如以下图所看到的: 最初的反应是电脑中毒了,于是使用360卫士.360杀毒对C盘查杀,由于明明记得C盘有40多G的可用空间才对.出现这 ...

  10. cocos2dx 3.x ccPositionTextureColor_vert与ccPositionTextureColor_noMVP_vert

    在cocos2dx 2.x中,如果我们要对sprite更换片段shader,写成: myProgram->initWithByteArrays(ccPositionTextureColor_ve ...