Thinkphp5源码解析试分析一部分
Thinkphp5框架默认入口为public目录下的index.php。
首先从index.php进行代码分析。
index.php(public目录下的index.php)代码如下:
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
//D:\phpStudy\WWW\tpfive\public __DIR__
// [ 应用入口文件 ]
/* 定义应用目录,定义了常量APP_PATH, __DIR__ 为魔术方法,获取当前执行的PHP脚本所在的目录
../application/ 返回上一级application目录里, */
define('APP_PATH', __DIR__ . '/../application/');
// 加载框架引导文件 载入thinkphp目录下的start.php文件
require __DIR__ . '/../thinkphp/start.php';
从index.php中加载了start.php。
start.php(thinkphp目录下的start.php)代码如下:
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
//首先定义了命名空间为think
namespace think;
// ThinkPHP 引导文件
// 1. 加载基础文件
//__DIR__指向当前执行的PHP脚本所在的目录,载入当前目录下的ba
se.php(\thinkphp\base.php)
require __DIR__ . '/base.php';
// 2. 执行应用 执行\thinkphp\library\think\App.php文件中的run方法
App::run()->send();
先分析start.php中的这句:
//__DIR__指向当前执行的PHP脚本所在的目录,载入当前目录下的base.php(\thinkphp\base.php)
require __DIR__ . '/base.php';
从start.php中加载了base.php。
base.php(thinkphp目录下的base.php)代码如下:
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
//这里定义了tp5的一些基本常量
//定义了当前tp框架的版本为'5.0.20',可在任意控制器或视图echo THINK_VERSION;获取框架版本号
define('THINK_VERSION', '5.0.20');
//microtime()返回当前 Unix 时间戳的微秒数,用于对php脚本的运行计时
define('THINK_START_TIME', microtime(true));
//memory_get_usage返回当前分配给你的 PHP 脚本的内存量,单位是字节(byte)
define('THINK_START_MEM', memory_get_usage());
//定义了.php后缀
define('EXT', '.php');
// DIRECTORY_SEPARATOR,路径分隔符,linux上是 "/" windows上是 "\"
define('DS', DIRECTORY_SEPARATOR);
//判断是否定义了常量THINK_PATH,没有则定义常量THINK_PATH为根目录下\thinkphp\
defined('THINK_PATH') or define('THINK_PATH', __DIR__ . DS);
//定义了library文件夹路径,根目录下\thinkphp\library\
define('LIB_PATH', THINK_PATH . 'library' . DS);
//定义常量CORE_PATH为根目录下\thinkphp\library\think\
define('CORE_PATH', LIB_PATH . 'think' . DS);
//定义了traits文件夹路径,根目录下\thinkphp\library\traits\
define('TRAIT_PATH', LIB_PATH . 'traits' . DS);
/* $_SERVER['script_FILENAME']获取的是当前执行脚本的绝对路径,不是当前PHP脚本所在的目录路径,
执行脚本指的是/public下的index.php,不是当前base.php文件,注意区分,dirname返回路径中的目录部分
这里APP_PATH常量在/public/index.php已经定义,
因此后面这句 define('APP_PATH', dirname($_SERVER['script_FILENAME']) . DS)不会执行
*/
defined('APP_PATH') or define('APP_PATH', dirname($_SERVER['script_FILENAME']) . DS);
//判断是否定义了常量ROOT_PATH,没有则定义常量ROOT_PATH为框架application目录所在的路径
defined('ROOT_PATH') or define('ROOT_PATH', dirname(realpath(APP_PATH)) . DS);
//判断是否定义了常量EXTEND_PATH,没有则定义常量EXTEND_PATH为框架extend目录所在的路径
defined('EXTEND_PATH') or define('EXTEND_PATH', ROOT_PATH . 'extend' . DS);
//判断是否定义了常量VENDOR_PATH,没有则定义常量VENDOR_PATH为框架vendor目录所在的路径
defined('VENDOR_PATH') or define('VENDOR_PATH', ROOT_PATH . 'vendor' . DS);
//判断是否定义了常量RUNTIME_PATH,没有则定义常量RUNTIME_PATH为框架runtime目录所在的路径
defined('RUNTIME_PATH') or define('RUNTIME_PATH', ROOT_PATH . 'runtime' . DS);
//判断是否定义了常量LOG_PATH,没有则定义常量LOG_PATH为框架\runtime\log所在的路径
defined('LOG_PATH') or define('LOG_PATH', RUNTIME_PATH . 'log' . DS);
//判断是否定义了常量CACHE_PATH,没有则定义常量CACHE_PATH为框架\runtime\cache目录所在的路径
defined('CACHE_PATH') or define('CACHE_PATH', RUNTIME_PATH . 'cache' . DS);
//判断是否定义了常量TEMP_PATH,没有则定义常量TEMP_PATH为框架\runtime\temp目录所在的路径
defined('TEMP_PATH') or define('TEMP_PATH', RUNTIME_PATH . 'temp' . DS);
//判断是否定义了常量CONF_PATH,没有则定义常量CONF_PATH为框架application目录所在的路径
defined('CONF_PATH') or define('CONF_PATH', APP_PATH); // 配置文件目录
//判断是否定义了常量CONF_EXT,没有则定义常量CONF_EXT为.php后缀
defined('CONF_EXT') or define('CONF_EXT', EXT); // 配置文件后缀
//判断是否定义了常量ENV_PREFIX,没有则定义常量ENV_PREFIX为PHP_
defined('ENV_PREFIX') or define('ENV_PREFIX', 'PHP_'); // 环境变量的配置前缀
//PHP_SAPI 用来判断是使用命令行还是浏览器执行的,nginx下PHP_SAPI输出cgi-fcgi,命令行输出cli
define('IS_CLI', PHP_SAPI == 'cli' ? true : false);
/*PHP_OS检查php运行环境,linux下输出linux,windows下输出WINNT
strpos是查找字符串WINNT下WIN的位置,找不到为false,说明当前运行环境不是windows系统 */
define('IS_WIN', strpos(PHP_OS, 'WIN') !== false);
// 载入\thinkphp\library\think\Loader.php文件
require CORE_PATH . 'Loader.php';
// 加载环境变量配置文件 根目录下的.env文件,默认.env文件没有,需要自行创建,.env是仿laravel框架的全局变量配置
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");
}
}
}
// 注册自动加载,执行上述载入\thinkphp\library\think\Loader.php文件中Loader类的register方法
\think\Loader::register();
/*注册错误和异常处理机制,由于当前php脚本没有Error这个类,因此触发了
\thinkphp\library\think\Loader.php文件Loader类中的register方法中
spl_autoload_register这个函数,而这个函数就会触发Loader类中的autoload方法,autoload方法会根据所该类,
找到该类对应的文件所在的目录,include进来,\think\Error会找到\thinkphp\library\think\Error.php文件
需要注意的是tp3.2中错误函数set_error_handler, 异常处理函数set_exception_handler,
php脚本执行完成函数register_shutdown_function都写在同一个类中,而tp5并没有写在当前类中,从当前类中分离出去
这三个函数写在了\thinkphp\library\think\Error.php文件里面,所以tp5比tp3加载的文件数量更多
*/
\think\Error::register();
/* \think\Config这个类在当前文件同样找不到,因此触发了
\thinkphp\library\think\Loader.php文件Loader类中的register方法,道理同上述一样
include了 \thinkphp\library\think\Config.php文件,执行Config.php文件中Config类中set方法,
加载惯例配置文件 载入 \thinkphp\convention.php文件里的配置*/
\think\Config::set(include THINK_PATH . 'convention' . EXT);
可以看出从base.php中加载了Loader.php。先分析base.php中这句重要的代码:
// 注册自动加载
\think\Loader::register();
全文:https://blog.csdn.net/bazhu3507/article/details/80745380