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没有这个问题呢,因为我们的中间件就是直接输出,并不像路由中间件这么处理。

转载于:https://www.cnblogs.com/xdao/p/slim_middleware_thinking.html

slimphp中间件调用流程的理解相关推荐

  1. linux 驱动probe 被调用流程分析 理解1

    原文链接:https://blog.csdn.net/goodnight1994/article/details/82082089 修改个别错误呈现 前言: 对于linux platform devi ...

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

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

  3. 理解Dubbo的调用流程与Dubbo多协议解析

    Dubbo作为目前国内主流的微服务框架之一 一.Dubbo的调用流程分析 Dubbo本身主要支持两种调用流程,包括直连提供者和基于注册中心的调用 直连提供者一般都是在开发和测试环境下使用 我们将所有的 ...

  4. RPC 笔记(01)— RPC概念、调用流程、RPC 与 Restful API 区别

    1. 基本概念 PRC 远程过程调用 Remote Procedure Call,其就是一个节点请求另外一个节点提供的服务.当两个物理分离的子系统需要建立逻辑上的关联时,RPC 是牵线搭桥的常见技术手 ...

  5. SDIO_WiFi驱动学习之安卓WLAN架构介绍及调用流程分析

    一.引言 上一篇博客介绍了MMC子系统和SDIO相关知识及架构,这一篇博客则分析一下安卓的WLAN架构及上层如何调用WLAN驱动的流程. 虽然我工作的开发环境是安卓系统,但由于我不是专业的安卓应用/框 ...

  6. RTSP播放器高RTSP兼容推流网页无插件流媒体播放器EasyPlayer-RTSP关于MP4的封装调用流程介绍

    EasyPlayer-RTSP播放器是一套RTSP专用的播放器,包括有:Windows(支持IE插件,npapi插件).Android.iOS三个平台,是区别于市面上大部分的通用播放器,EasyPla ...

  7. Linux ALSA声卡驱动之七:录音(Capture) 调用流程

    ALSA声卡驱动: 1.Linux ALSA声卡驱动之一:ALSA架构简介和ASOC架构简介 2.Linux ALSA声卡驱动之二:Platform 3. Linux ALSA声卡驱动之三:Platf ...

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

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

  9. 对ajax中onreadystatechange事件执行流程的理解

    对Ajax中onreadystatechange事件执行流程的理解 onreadystatechange 事件 当请求被发送到服务器时,我们需要执行一些基于响应的任务. 每当 readyState 改 ...

最新文章

  1. Linux网络编程--TCP中的三次握手和四次挥手
  2. PHP开发之环境配置
  3. Android NDK-helloJNI
  4. zemax评价函数编辑器_ZEMAX与光学设计案例:激光扩束系统详细设计与公差分析(二)...
  5. java用中根后根序列构造二叉树,106. 从中序与后序遍历序列构造二叉树
  6. c++创建二叉树_数据结构:查找(4)|| 平衡二叉树
  7. 华为应用锁退出立即锁_华为P40系列三大安全锁,教你锁住你的隐私 - 企业资讯...
  8. python中的优化器有哪些_Python SciPy 优化器(Optimizers)
  9. android裁剪部分放大动画,【Android】图片放大被截了一部分之认识clipChildren属性的用法...
  10. 数学建模——什么是数学建模
  11. 遥感图像预处理—步骤
  12. 怎么看电脑的hdmi是输出还是输入_笔记本hdmi接口是输入还是输出
  13. shell中各种括号的作用详解()、(())、[]、[[]]、{}(推荐)
  14. 世界三大顶级音响_世界音响三个顶尖品牌 世界顶级音响哪个品牌好
  15. 删除一个字符串中指定位置上的字符
  16. 北航 计算机学院 加试两门,北航强军计划考研计算机学院招生.pdf
  17. winform 异步加载控件屏幕一闪一闪亮晶晶解决
  18. 教你破解隔壁妹子wifi密码,成功率高达90%
  19. 桂电的计算机专业研究生录取比例,桂电研究生就业待遇 桂林电子科技大学就业率...
  20. 网卡反复重启[why!why!why]

热门文章

  1. win7下安装redies
  2. 在Apache Tomcat 7设置redis作为session store
  3. 【开发技术】视频URL采集
  4. Windows Server 2008 使用WDS自动部署操作系统
  5. oracle数据误操作恢复【flashback闪回操作】
  6. 【Python-ML】SKlearn库网格搜索和交叉验证
  7. Linux命令ps解读
  8. ubuntu15.10安装wireshark
  9. Manage Common Field Service Jobs
  10. Maven安装、配置、项目创建、编译等相关操作