请求处理
return $this->app->route->dispatch($request, $withRoute);
这里就是处理整个业务的核心,之前的事件注册,路由注册,中间件注册,都会在这里执行。可能会涉及很多细节,但在这里不会细说,主要看一下整个分发的流程。看一下 dispatch 方法的代码
public function dispatch(Request $request, $withRoute = null)
{
$this->request = $request;
// 1
$this->host = $this->request->host(true);
// 2
$this->init();
// 3
if ($withRoute) {
$checkCallback = function () use ($request, $withRoute) {
$withRoute();
return $this->check();
};
if ($this->config['route_check_cache']) {
$dispatch = $this->cache
->tag('route_cache')
->remember($this->getRouteCacheKey($request), $checkCallback);
} else {
$dispatch = $checkCallback();
}
} else {
$dispatch = $this->url($this->path());
}
// 4
$dispatch->init($this->app);
$this->app->middleware->add(function () use ($dispatch) {
try {
$response = $dispatch->run();
} catch (HttpResponseException $exception) {
$response = $exception->getResponse();
}
return $response;
});
return $this->app->middleware->dispatch($request);
}
按照 1 ~ 4 步骤进行说明
获取域名不含端口号
初始化
route 的初始化
加载配置文件 route.php
路由是否延迟解析
设置路由缓存
如果生成了路由缓存文件就加载路由缓存文件 => runtime 目录下的 route.php
是否开启路由
开启路由缓存 ,加载路由文件并且检测 URL,设置路由缓存 key 的还会将对应路由缓存起来。
注意的是,remember 方法会执行闭包,所以存储的并不是闭包,而是 dispatch\url 对象
获取路由缓存的 key,这个是在配置文件设置的,还必须是设置闭包。
如果没有开启路由 直接解析 URL
dispatch 初始化
因为 $dispatch instanceof dispatch\Controller 所以主要初始化工作在 Controller 里面
将调度追加到中间件 middleware queue 队列中,所以这一步最近才会执行
中间件调度执行
未启用路由
当前所在 think\Route 类中,再往下讲之前,先来看一下 url 这个方法。
public function url(string $url): UrlDispatch
{
return new UrlDispatch($this->request, $this->group, $url);
}
这段代码很重要,因为请求在没有启用路由的情况是由它处理。$this->group 属性呢就是在当前类实例化的时候设置的 think\route\Domain 域名路由类。$url 是从 pathinfo 信息中获取的。了解了这些信息之后,直接看到步骤 4,因为上面的步骤最终目的都是获得这个 dispatch 对象。
启用路由的情况
启动路由的情况会产生另外一个 Dispatch 对象 think\route\dispatch\Callback,为什么会产生两个不同对象,具体细节在之后的路由解析中会详细介绍,先跳过细节,看看整个过程是如何处理的。下面会分别介绍两个对象的处理。
DisPatch 的初始化
上述两种情况下,获取控制和模块的方法是完全不一样。
前者是直接解析 URL 来获取,就是框架以前传统的方式 module/controller/index,然后解析出来。
后者是经过路由解析之后,才会获取相应模块的控制器,这部分有一定性能消耗。
所以对比来看,未启用路由性能比较高,但是还是推荐启用路由,这样比较易于管理。
Dispatch 执行
因为 Dispatch run 作为闭包被加入到中间的队列中之后,由中间件 Dispatch。关于中间执行可以参照上篇,这里需要知道的是 Dispatch 是被加到中间件队列末尾,是在最后执行的就可以了。
主要来看 $dispatch->run(),上文说的两个对象都是继承 Dispatch 对象的,所以到里面看看 run 方法。
public function run(): Response
{
if ($this->rule instanceof RuleItem && $this->request->method() == 'OPTIONS' && $this->rule->isAutoOptions()) {
$rules = $this->rule->getRouter()->getRule($this->rule->getRule());
$allow = [];
foreach ($rules as $item) {
$allow[] = strtoupper($item->getMethod());
}
return Response::create('', '', 204)->header(['Allow' => implode(', ', $allow)]);
}
$option = $this->rule->getOption();
// 数据自动验证
if (isset($option['validate'])) {
$this->autoValidate($option['validate']);
}
$data = $this->exec();
return $this->autoResponse($data);
}
启用路由和未启用路由完全是两种过程,启用理由设计到路由解析的过程,暂且搁置,后面详细说明。下面的过程是指的未启用路由的过程。
通过 URL 获取访问路径,例如 index/index
对于这样的 URL 默认会访问配置文件 route.php 的 controller_layer 所设置的目录下的类文件。框架默认设置的是 controller。创建框架的时候应该就可以看到了。
对于控制器而言可以设置控制器的中间件,对于控制器中间件作用范围应该是执行方法之前,控制器初始化后。
设置空控制器,默认是 Error,这个似乎和以前的版本是一样的。
这两种方式的区别,路由访问带来了一定的自由目录组织的能力,当然性能会有所损耗,Url 访问可能限制相对而言不是那么自由,比如对于初始化框架你只能限定在 controller 目录下创建类使用。当然这个是可以改变的,使用框架在初始化的先后循序上做一下改变,以应对框架的在 URL 解析上的规则,这个将会在下一篇事件机制上作出解答
- 空白目录
- php语法结构
- 安装与更新
- 开启调试模式及代码跟踪器
- 架构
- 源码分析
- 应用初始化
- 请求流程
- 中间件源码分析
- 请求处理源码分析
- Request源码分析
- 模板编译流程
- 路由与请求流程
- 容器
- 获取目录位置
- 入口文件
- 多应用模式及URL访问
- 依赖注入与容器
- 容器属性及方法
- Container
- App
- facade
- 中间件(middleware)
- 系统服务
- extend 扩展类库
- 笔记
- 配置
- env配置定义及获取
- 配置文件的配置获取
- 单应用模式-(配置)文件目录结构(默认)
- 多应用模式(配置)文件目录结构(配置文件)
- 配置文件
- 应用配置:app.php
- 缓存配置: cache.php
- 数据库配置:database.php
- 路由和URL配置:route.php
- Cookie配置:cookie.php
- Session配置:session.php
- 命令行配置:console.php
- 多语言配置:lang.php
- 日志配置:log.php
- 页面Trace配置:trace.php
- 磁盘配置: filesystem.php
- 中间件配置:middleware.php
- 视图配置:view.php
- 改成用yaconf配置
- 事件
- 例子:省略事件类的demo
- 例子2:完整事件类
- 例子3:事件订阅,监听多个事件
- 解析
- 路由
- 路由定义
- 路由地址
- 变量规则
- MISS路由
- URL生成
- 闭包支持
- 路由参数
- 路由中间件
- 路由分组
- 资源路由
- 注解路由
- 路由绑定
- 域名路由
- 路由缓存
- 跨域路由
- 控制器
- 控制器定义
- 空控制器、空操作
- 空模块处理
- RESTFul资源控制器
- 控制器中间件
- 请求对象Request(url参数)
- 请求信息
- 获取输入变量($_POST、$_GET等)
- 请求类型的获取与伪装
- HTTP头信息
- 伪静态
- 参数绑定
- 请求缓存
- 响应对象Response
- 响应输出
- 响应参数
- 重定向
- 文件下载
- 错误页面的处理办法
- 应用公共文件common.php
- 模型
- 模型定义及常规属性
- 模型数据获取与模型赋值
- 查询
- 数据集
- 增加
- 修改
- 删除
- 条件
- 查询范围scope
- 获取器
- 修改器
- 搜索器
- 软删除
- 模型事件
- 关联预载入
- 模型关联
- 一对一关联
- 一对多关联
- 多对多关联
- 自动时间戳
- 事务
- 数据库
- 查询构造器
- 查询合集
- 子查询
- 聚合查询
- 时间查询
- 视图查询(比join简单)
- 获取查询参数
- 快捷方法
- 动态查询
- 条件查询
- 打印sql语句
- 增
- 删
- 改
- 查
- 链式操作
- 查询表达式
- 分页查询
- 原生查询
- JSON字段
- 链接数据库配置
- 分布式数据库
- 查询事件
- Db获取器
- 事务操作
- 存储过程
- Db数据集
- 数据库驱动
- 视图
- 模板
- 模板配置
- 模板位置
- 模板渲染
- 模板变量与赋值(assign)
- 模板输出替换
- url生成
- 模板详解
- 内置标签
- 三元运算
- 变量输出
- 函数输出
- Request请求参数
- 模板注释及原样输出
- 模板继承
- 模板布局
- 原生PHP
- 模板引擎
- 视图过滤
- 视图驱动
- 验证
- 验证进阶之最终版
- 错误和日志
- 异常处理
- 日志处理
- 调试
- 调试模式
- Trace调试
- SQL调试
- 变量调试
- 远程调试
- 杂项
- 缓存
- Session
- Cookie
- 多语言
- 上传
- 扩展说明
- N+1查询
- TP类库
- 扩展类库
- 数据库迁移工具
- Workerman
- think助手工具库
- 验证码
- Swoole
- request
- app
- Response
- View
- Validate
- Config
- 命令行
- 助手函数
- 升级指导(功能的添加与删除说明)
- siyucms
- 开始
- 添加页面流程
- 列表页加载流程
- 弹出框
- 基础控制器
- 基础模型
- 快速构建
- 表单form构建
- 表格table构建
- MakeBuilder
- 前端组件
- 日期组件
- layer 弹层组件
- Moment.js 日期处理插件
- siyucms模板布局
- 函数即其变量
- 前端页面
- $.operate.方法
- $.modal.方法:弹出层
- $.common.方法:通用方法
- 被cms重写的表格options
- 自定义模板
- 搜索框
- 自定义form表单
- 获取表单搜索参数并组装为url字符串