App Runtime
一个Slim应用由类Slim\Slim
的一个实例贯穿始终。
Construct A Slim Application
在构造一个Slim\Slim
实例的时候,我们做了如下的操作。
- 设定依赖容器
\Slim\Helper\Set
- 初始化系统级的依赖
- settings
- environment
- request
- response
- router
- view
- logWriter
- log
- 初始化系统中间件stack
Set Routes’ List for Future Request Dispatch
构造Slim类的实例之后,应用开始对路由进行配置。
路由的配置需要最少三样事物,
- 请求方法
- 匹配uri
- 处理函数
这里仅就GET方法进行举例,POST/DELETE/PUT/OPTION/PATCH的方法与GET类似,只是via
后面的参数会发生变化。
最终,这些请求的参数都是转发到mapRoute
方法上。
mapRoute
方法使用用户设定的路由参数,构造一个Slim\Route
实例,并返回给前置的设定方法,设定该路由所适配的HTTP请求。
其中group部分的实现很有意思,由于Slim在设置路由组的时候可以嵌套,比如下述结构:
路由组group实现了一个先进后出的stack结构。
Router类的实现参见下述代码,如果存在多级的group,那么Router::$routeGroups
会保存这些多级的group。
单个路由在调用mapRoute
的时候,会从Router
中调用map
方法,这个方法就是向单个的路由添加当前存在routeGroups
的路由组的pattern和路由中间件。
Run App
Slim实例在完成路由设置后,就可以进入运行阶段了。
核心部分大概只有一行$this->middleware[0]->call();
,执行中间件stack的代码。由于Slim应用实例自身位于stack底部,所以最终执行的是Slim::call()
。
这段代码基本按照注释的流程执行的,其中重要的是以下三点
Get matched routes
Router
是Slim框架里解析路由的类,其实例的getMatchedRoutes()
方法接受两个参数:Http Method和请求Uri。
对于每个Request而言,其Uri和请求方法都是唯一的。
getMatchedRoutes()
方法将遍历Router实例中的routes
属性,即应用设定的每一个路由;对于路由列表里面的每一个路由,首先判断是否支持Request的请求方法,然后判断相应的Uri是否匹配。
判断Uri是否匹配使用了类Route
的matches()
方法,主要原理是将设定的路由转换成一个正则表达式,然后进行正则匹配。 其中,如果遇到变量的标识:
和变量组标识+
会调用matchesCallback()
进行特殊替换。
Dispatch request
这一部分的代码主要就是分发Request信息到匹配到的路由上,并执行绑定的路由中间件和闭包函数。
Output response
Slim实例将output buffer中的数据使用ob_get_clean
收集完成,并将其放入到Response的实例中。
之后在Slim::run()
方法中,通过调用Response::finalize()
方法将生成的响应状态、头部、内容返回给Slim实例,然后再输出出去。
这样,一个完整的请求流程就完成了。
Tips
最后补上一张图。