App类可以说是总框架的第二个真正入口了,所有的框架逻辑操作都在这里完成。这也是为什么我要把他提在其他核心组件类之前分析的原因。我们先看入口文件start.php代码:
require __DIR__ . '/base.php';
App::run()->send();
base.php在第一章里已经说了,做了前期的准备工作(定义系统必要的常量以及注册自动加载),然后就执行App的run然后send。这篇就说下一个请求从开始到结束的整个流程run做了什么,主要涉及到Request、route。也建议大家先看下base.php定义的常量以及config配置。这里是官方给出的更详细的参考文档:
常量定义:http://www.kancloud.cn/manual/thinkphp5/118137
配置参考:http://www.kancloud.cn/manual/thinkphp5/118136
PS:下文提到EXT均为文件后缀定义,TP为当前讲述的框架
对app::run()做一个流程性的总结阐述:
流程代码有做精简,略去业务性的判断以及更好展现流程代码优化
1.1、加载当前模块(module)下的初始化文件({$module}init.EXT)在我理解,(我觉得这个文件官方意图是希望我们框架使用者将其他的一些功能性的配置文件以及自定义一些必要的内容进行一个集合式的加载。当如如果这个文件不存在直接读取其下面指定的文件)见代码:
init($module = '') {
is_file($current_module . 'init' . EXT) {
//这玩意其实可以自定义的将下面这些东西整合起来打包
include $module . 'init' . EXT;
} else {
$config = Config::load($module . 'config' . CONF_EXT);
//app状态环境的一个配置开发环境、生产环境、测试环境等不同配置
if ($config['app_status']) {
$config = Config::load($module . $config['app_status'] . CONF_EXT);
}
//读取扩展配置文件 当然你必须在$config里面定义了extra_config_list
foreache($config['extra_config_list'] as $config){
Config::load($module . $config . CONF_EXT);
}
//加载别名文件 $module . 'alias' . EXT
Loader::addClassMap(include $module . 'alias' . EXT);
//加载行为扩展文件
Hook::import($module . 'tags' . EXT);
//// 加载别名文件
include $module. 'common' . EXT;
//加载语言包
Lang::load( 'lang' . {$lang_type} . EXT);
}
return Config::get();
}
1.2、读取配置里面的也就是1.1的配置命名空间相关配置、额外其他文件进行加载见代码:
initCommon(){
$config = self::init();
//调试模式设置
self::$debug = Config::get('app_debug');
…………
//命名空间加载(这里说下这里加载是对命名空间自定义简化或者其他想法进行的一个key=>value配置加载)
Loader::addNamespace($config['app_namespace'], APP_PATH);
//设置系统时区
date_default_timezone_set($config['default_timezone']);
self::$init = $config;
return self::$init;
}
2、根据请求URL以及配置config分析出调度信息(也就是当前操作状态、模块、控制器、操作、参数)
run(Request $request = null){
//单例个Request对象
is_null($request) && $request = Request::instance();
//这个就是 part1 了
$config = self::initCommon();
try {
//多语言
Lang::load(THINK_PATH . 'lang' . DS . $request->langset() . EXT);
//获取调度信息 这个Request就是刚才的对象 准备去routeCheck里面干大事去
/*
routcheck返回的调度信息大致这样的 当然type是正常请求controller/action 其他类型后讲
$dispatch = [
'type' => 'module',
'module' => [
{$module}, {$controller}, {$action.$params}
]
]
*/
$check = !is_null(self::$routeCheck) ? self::$routeCheck : $config['url_route_on'];
……
}
}
routeCheck($request, array $config){
……
//Request::path获取http $_SERVER以及根据config配置参数进行处理
/*
$path = '{$module}/{$controller}/{$action}?{$param1}={$val1}&{$param2}={$val2}……'
*/
$path = $request->path();
//pathinfo 定义的分隔符 去补习手册配置吧
$depr = $config['pathinfo_depr'];
$result = false;
//路由检测
$check = !is_null(self::$routeCheck) ? self::$routeCheck : $config['url_route_on'];
if($check) {
//路由配置导入
Route::import($config['route']);
//路由检测 详细见Route类源码分析
$result = Route::check($request, $path, $depr, $config['url_domain_deploy']);
//强制走路由配置
$must = $config['url_route_must'];
if ($must && false === $result) {
//GG……route not found
}
}
if (false === $result) {
// 路由无效 解析模块/控制器/操作/参数... 支持控制器自动搜索 就是对请求url进行按照规则进行整理 详route类
$result = Route::parseUrl($path, $depr, $config['controller_auto_search']);
}
return $result;
}
3、进行分发调度执行。
run(Request $request = null){
is_null($request) && $request = Request::instance();
$config = self::initCommon();
try {
Lang::load(THINK_PATH . 'lang' . DS . $request->langset() . EXT);
$dispatch = self::routeCheck($request, $config);
……
switch($dispatch['type']){
……
//进行请求调度
case 'module':
$data = self::module($dispatch['module'], $config, isset($dispatch['convert']) ? $dispatch['convert'] : null);
break;
……
default:
throw new \InvalidArgumentException('dispatch type not support');
}catch (HttpResponseException $exception) {
$data = $exception->getResponse();
}
Loader::clearInstance();
……
return $response;
}
}
下一章会着重App::module进行分析,会穿插Route相关内容。
网友评论