[TOC]
* * * * *
#1 启动概述
* 启动的总流程按照文件分为三步
* 1 请求入口(public/index.php)
* 2 框架启动(thinkphp/start.php)
* 3 应用启动 (thinkphp/library/App.php)
#2 入口文件(public/index.php)
~~~
// 定义应用目录
define('APP_PATH', __DIR__ . '/../application/');
// 加载框架引导文件
require __DIR__ . '/../thinkphp/start.php';
~~~
> 默认的入口文件在public/index.php
>> 主要定义应用目录,加载框架引导文件(thinkphp/start.php)
#3 框架启动(thinkphp/start.php)
## 3-1 框架引导(thinkphp/start.php)
~~~
// 加载基础文件
require __DIR__ . '/base.php';
// 执行应用
App::run()->send();
~~~
> 框架引导文件(thinkphp/start.php)
>>主要用来启动框架
>>按照涉及的文件分为以下三步
>>1 定义全局变量与注册自动加载
>>2 加载默认配置
>>3 启动应用
## 3-2 定义全局常量(thinkphp/base.php)
~~~
define('THINK_VERSION', '5.0.0');
define('THINK_START_TIME', microtime(true));
define('THINK_START_MEM', memory_get_usage());
define('EXT', '.php');
define('DS', DIRECTORY_SEPARATOR);
defined('THINK_PATH') or define('THINK_PATH', __DIR__ . DS);
define('LIB_PATH', THINK_PATH . 'library' . DS);
define('CORE_PATH', LIB_PATH . 'think' . DS);
define('TRAIT_PATH', LIB_PATH . 'traits' . DS);
defined('APP_PATH') or define('APP_PATH', dirname($_SERVER['SCRIPT_FILENAME']) . DS);
defined('ROOT_PATH') or define('ROOT_PATH', dirname(APP_PATH) . DS);
defined('EXTEND_PATH') or define('EXTEND_PATH', ROOT_PATH . 'extend' . DS);
defined('VENDOR_PATH') or define('VENDOR_PATH', ROOT_PATH . 'vendor' . DS);
defined('RUNTIME_PATH') or define('RUNTIME_PATH', ROOT_PATH . 'runtime' . DS);
defined('LOG_PATH') or define('LOG_PATH', RUNTIME_PATH . 'log' . DS);
defined('CACHE_PATH') or define('CACHE_PATH', RUNTIME_PATH . 'cache' . DS);
defined('TEMP_PATH') or define('TEMP_PATH', RUNTIME_PATH . 'temp' . DS);
defined('CONF_PATH') or define('CONF_PATH', APP_PATH); // 配置文件目录
defined('CONF_EXT') or define('CONF_EXT', EXT); // 配置文件后缀
defined('ENV_PREFIX') or define('ENV_PREFIX', 'PHP_'); // 环境变量的配置前缀
// 环境常量
define('IS_CLI', PHP_SAPI == 'cli' ? true : false);
define('IS_WIN', strpos(PHP_OS, 'WIN') !== false);
~~~
>>基础文件(thinkphp/base.php)
>>开始部分定义了框架的全局常量
>>包括框架的运行信息,目录组织,运行环境等
## 3-3 注册自动加载(thinkphp/base.php)
~~~
// 载入Loader类
require CORE_PATH . 'Loader.php';
// 加载环境变量配置文件
if (is_file(ROOT_PATH . '.env')) {
$env = parse_ini_file(ROOT_PATH . '.env', true);
foreach ($env as $key => $val) {
$name = ENV_PREFIX . strtoupper($key);
if (is_array($val)) {
foreach ($val as $k => $v) {
$item = $name . '_' . strtoupper($k);
putenv("$item=$v");
}
} else {
putenv("$name=$val");
}
}
}
// 注册自动加载
\think\Loader::register();
// 注册错误和异常处理机制
\think\Error::register();
~~~
>> 基础文件(thinkphp/base.php)
>> 中间部分加载环境配置,
>> 启动自动加载
>> 注册自定义错误与异常处理
## 3-4 加载框架默认配置(thinkphp/convention.php)
~~~
\think\Config::set(include THINK_PATH . 'convention' . EXT);
~~~
>>基础文件(thinkphp/base.php)
>>最后加载框架默认配置
## 3-5 框架默认配置(thinkphp/convention.php)
~~~
应用设置
模块设置
URL设置
模板设置
异常及错误设置
日志设置
Trace设置
缓存设置
会话设置
Cookie设置
数据库设置
分页配置
~~~
>>以数组形式实现框架默认配置
>>相关配置信息可以在应用目录(application/)中进行覆盖
#4 应用启动(thinkphp/library/App.php)
## 4-1 请求分析(App.php->run())
~~~
App.php;
public static function run(Request $request = null)
is_null($request) && $request = Request::instance();
$config = self::initCommon();
if (defined('BIND_MODULE')) {
// 模块/控制器绑定
BIND_MODULE && Route::bind(BIND_MODULE);
} elseif ($config['auto_bind_module']) {
// 入口自动绑定
$name = pathinfo($request->baseFile(), PATHINFO_FILENAME);
if ($name && 'index' != $name && is_dir(APP_PATH . $name)) {
Route::bind($name);
}
}
$request->filter($config['default_filter']);
。。。。。。
}
~~~
>> 应用启动的请求分析
>> 首先 创建请求对象(Request)
>> 然后 解析请求的模块信息
>> 最后 过滤请求信息
## 4-2 应用调度(App.php->run())
~~~
App.php;
public static function run(Request $request = null)
。。。。。。
try {
// 开启多语言机制
if ($config['lang_switch_on']) {
// 获取当前语言
$request->langset(Lang::detect());
// 加载系统语言包
Lang::load(THINK_PATH . 'lang' . DS . $request->langset() . EXT);
if (!$config['app_multi_module']) {
Lang::load(APP_PATH . 'lang' . DS . $request->langset() . EXT);
}
}
// 获取应用调度信息
$dispatch = self::$dispatch;
if (empty($dispatch)) {
// 进行URL路由检测
$dispatch = self::routeCheck($request, $config);
}
// 记录当前调度信息
$request->dispatch($dispatch);
// 记录路由和请求信息
if (self::$debug) {
Log::record('[ ROUTE ] ' . var_export($dispatch, true), 'info');
Log::record('[ HEADER ] ' . var_export($request->header(), true), 'info');
Log::record('[ PARAM ] ' . var_export($request->param(), true), 'info');
}
// 监听app_begin
Hook::listen('app_begin', $dispatch);
switch ($dispatch['type']) {
case 'redirect':
// 执行重定向跳转
$data = Response::create($dispatch['url'], 'redirect')->code($dispatch['status']);
break;
case 'module':
// 模块/控制器/操作
$data = self::module($dispatch['module'], $config, isset($dispatch['convert']) ? $dispatch['convert'] : null);
break;
case 'controller':
// 执行控制器操作
$data = Loader::action($dispatch['controller']);
break;
case 'method':
// 执行回调方法
$data = self::invokeMethod($dispatch['method']);
break;
case 'function':
// 执行闭包
$data = self::invokeFunction($dispatch['function']);
break;
case 'response':
$data = $dispatch['response'];
break;
default:
throw new \InvalidArgumentException('dispatch type not support');
}
} catch (HttpResponseException $exception) {
$data = $exception->getResponse();
}
。。。。。。
}
~~~
>>应用启动的应用调度
>>首先 检查语言配置
>>然后 路由解析获取调度信息
>>最后 根据调度类型执行不同类型应用
## 4-3 数据输出(App.php->run())
~~~
App.php;
public static function run(Request $request = null)
// 清空类的实例化
Loader::clearInstance();
// 输出数据到客户端
if ($data instanceof Response) {
$response = $data;
} elseif (!is_null($data)) {
// 默认自动识别响应输出类型
$isAjax = $request->isAjax();
$type = $isAjax ? Config::get('default_ajax_return') : Config::get('default_return_type');
$response = Response::create($data, $type);
} else {
$response = Response::create();
}
// 监听app_end
Hook::listen('app_end', $response);
return $response;
。。。。。。
}
~~~
>>应用逻辑执行完后,
>>首先 清空应用执行过程创建的对象
>>然后 根据应用执行后返回的数据创建响应对象(Response)
>>最后 调用相应对象的send()输出数据到客户端(start.php文件中)