ThinkPHP框架系统源码解析——URL路由解析
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ThinkPHP框架系统源码解析——URL路由解析相关的知识,希望对你有一定的参考价值。
1 一、Thinkphp框架目录 2 /test/index.php //项目入口文件 3 /ThinkPHP/ThinkPHP.php //框架入口文件 4 5 Common 框架公共文件目录(函数库) 6 ThinkPHP/Common/runtime.php //框架初次运行文件 7 ThinkPHP/Common/common.php //框架基础函数库 8 ThinkPHP/Common/functions.php //标准模式公共函数库 9 10 Conf 框架配置文件目录 11 ThinkPHP/Conf/convention.php //惯例配置文件,系统默认配置小于项目配置 12 ThinkPHP/Conf/debug.php //默认的调试模式配置文件 13 14 Lang 框架系统语言目录 15 16 Lib 系统核心基类库目录 17 ThinkPHP/Core/Think.class.php //入口文件(设置异常和错误处理机制、注册系统自动加载机制、预编译当前项目、加载框架惯例配置文件) 18 ThinkPHP/Lib/Core/Log.class.php, // 日志处理类 19 ThinkPHP/Lib/Core/Dispatcher.class.php, // URL调度类 20 ThinkPHP/Lib/Core/App.class.php, // 应用程序类 21 ThinkPHP/Lib/Core/Action.class.php, // 控制器类 22 ThinkPHP/Lib/Core/View.class.php, // 视图类 23 24 Tpl 系统模板目录 25 ThinkPHP/Tpl/default_index.tpl //测试模块的模板 26 ThinkPHP/Tpl/dispatch_jump.tpl //页面提示的模板 27 ThinkPHP/Tpl/page_trace.tpl //页面Trace信息的模板 28 ThinkPHP/Tpl/think_exception.tpl //系统错误信息的模板 29 30 Extend 框架扩展目录 31 32 33 <?php 34 /* 35 * 1、用户访问网站URL地址 36 * /test/Index.php 项目入口文件 37 */ 38 require (‘../ThinkPHP/ThinkPHP.php‘);//引入框架文件 39 40 41 42 43 /* 44 * 2、载入系统入口文件ThinkPHP.php 45 * ThinkPHP/ThinkPHP.php框架入口文件 46 * 判断系统常量,如果没有定义则自动生成 47 */ 48 $GLOBALS[‘_beginTime‘] = microtime(TRUE); //记录运行时的时间 49 50 51 define(‘MEMORY_LIMIT_ON‘,function_exists(‘memory_get_usage‘));//php中用echo memory_get_usage() 获取当前的内存消耗量 52 53 54 if(MEMORY_LIMIT_ON) $GLOBALS[‘_startUseMems‘] = memory_get_usage();//如果支持内存使用量函数则全局变量$GLOBALS[‘_startUseMems‘]等于内存使用量,这里相当于记录下内存初始使用的量 55 56 57 defined(‘APP_PATH‘) or define(‘APP_PATH‘, dirname($_SERVER[‘SCRIPT_FILENAME‘]).‘/‘);//设置当前的项目路径 58 59 60 defined(‘RUNTIME_PATH‘) or define(‘RUNTIME_PATH‘,APP_PATH.‘Runtime/‘);//设置runtime的路径 61 62 63 defined(‘APP_DEBUG‘) or define(‘APP_DEBUG‘,false); // 是否调试模式,默认false 64 65 66 $runtime = defined(‘MODE_NAME‘)?‘~‘.strtolower(MODE_NAME).‘_runtime.php‘:‘~runtime.php‘;//如果设置了其它运行模式则~ruturn.php就变化为 ~模式ruturn.php,(例如,采用命令行模式运行),那么在入口文件中定义MODE_NAME如下define(‘MODE_NAME‘,‘cli‘); 那么这里的缓存文件就为~cliruturn.php 67 68 69 defined(‘RUNTIME_FILE‘) or define(‘RUNTIME_FILE‘,RUNTIME_PATH.$runtime);//设置~runtime.php的路径; 70 71 72 if(!APP_DEBUG && is_file(RUNTIME_FILE)) { 73 // 部署模式直接载入运行缓存 74 require RUNTIME_FILE; 75 }else{//高度模式下加载框架下的Common/runtime.php文件;我们就模拟程序第一次运行,从下面开始进入 76 // 系统目录定义 77 defined(‘THINK_PATH‘) or define(‘THINK_PATH‘, dirname(__FILE__).‘/‘); 78 // 加载运行时文件,载入系统运行时文件runtime.php并定义项目路径常量 79 require THINK_PATH.‘Common/runtime.php‘; 80 } 81 82 /* 83 * 3、载入系统运行时文件runtime.php并定义项目路径常量 84 * ThinkPHP/Common/runtime.php 系统运行时文件 85 * ThinkPHP 运行时文件 编译后不再加 86 */ 87 88 89 //从18——81行定义了程序中要用到的各种常量 90 91 92 //#84行 为了方便导入第三方类库 设置Vendor目录到include_path 93 set_include_path(get_include_path() . PATH_SEPARATOR . VENDOR_PATH);//这一句将/ThinkPHP/Extend/Vendor/ 加入了include_path目录中 94 95 96 //#87-114行 加载运行时所需要的文件 并负责自动目录生成 97 function load_runtime_file() { 98 //引入/ThinkPHP/Lib/Core/Think.class.php 99 //引入/ThinkPHP/Lib/Core/ThinkException.class.php, // 异常处理类 100 //引入/ThinkPHP/Lib/Core/Behavior.class.php, 101 // 检查项目目录结构 如果不存在则自动创建 build_app_dir();check_runtime(); 102 103 104 } 105 106 107 //#118-130行 // 检查缓存目录(Runtime) 如果不存在则自动创建 108 function check_runtime() { 109 // 在load_runtime_file()中被引用 110 } 111 112 113 //#133-163行 //创建编译缓存 114 function build_runtime_cache($append=‘‘) { 115 //没仔细研究,是把程序中用到的代码都压入到~return.php缓存文件中 116 } 117 118 119 //#164-174 //// 编译系统行为扩展类库 120 function build_tags_cache() { 121 //编译系统行为扩展类库 compile($filename)此函数 122 } 123 124 125 //117-224 // 创建项目目录结构 126 function build_app_dir(){ 127 //创建项目目录结构 128 } 129 130 131 //227-230 // 创建测试Action 132 function build_first_action(){ 133 // /ThinkPHP/Tpl/default_index.tpl模板 134 } 135 136 137 //#233 加载运行时所需文件 138 load_runtime_file(); 139 140 141 //#235 记录加载文件时间 142 G(‘loadTime‘); 143 144 145 // 执行入口 146 Think::Start(); 147 148 149 /* 150 * 执行入口 151 * /ThinkPHP/Lib/Core/Think.class.php 152 * 程序的入口(设置异常和错误处理机制、注册系统自动加载机制、预编译当前项目、加载框架惯例配置文件) 153 */ 154 155 156 //#37-49 应用程序初始化 157 static public function Start() { 158 // 设定错误和异常处理 159 set_error_handler(array(‘Think‘,‘appError‘)); //将this->appError()注册为错误处理方法 160 set_exception_handler(array(‘Think‘,‘appException‘)); //将$this->appException()注册为异常处理函数 161 // 注册AUTOLOAD方法 162 spl_autoload_register(array(‘Think‘, ‘autoload‘));//将$this->autoload()注册为__autoload()方法 163 //[RUNTIME] 164 Think::buildApp(); // 读取配置信息 预编译项目 165 //[/RUNTIME] 166 // 运行应用 167 App::run(); 168 return ; 169 } 170 171 172 //#61-124 读取配置信息 预编译项目 173 static private function buildApp() { 174 // /ThinkPHP/Conf/convention.php 读取系统配置,读取项目配置 /项目/Conf/conf.php 合并配置 175 //加载语言包(可能是支持多语言的,目前没用到过) 176 //加载模式系统行为定义(没看明白) 177 //读取核心编译文件列表 (使用compile()函数,将所有核心类及函数、自定义类库压入到$compile变量中,等待编译~runtime.php) 178 ( 179 ThinkPHP/Common/functions.php, // 标准模式函数库 180 ThinkPHP/Lib/Core/Log.class.php, // 日志处理类 181 ThinkPHP/Lib/Core/Dispatcher.class.php, // URL调度类 182 ThinkPHP/Lib/Core/App.class.php, // 应用程序类 183 ThinkPHP/Lib/Core/Action.class.php, // 控制器类 184 ThinkPHP/Lib/Core/View.class.php, // 视图类 185 ); 186 // ThinkPHP/Common/common.php //加载项目公共文件(函数库) 187 // 项目/Conf/alias.php 加载项目别名定义(项目自定义类库,用别名导入的方式引入的自定义类库) 188 // 如果是调试模式,加载系统默认的配置文件ThinkPHP/Conf/debug.php的默认调试配置,如果项目自己定义了 项目/Conf/debug.php则读取项目调试配置 189 // 最后如果是部署模式 使用build_runtime_cache($compile); 创建编译缓存,将$compile变量写入到项目/Runtime/~runtime.php文件中 190 // 欧克至此该引入的文件全部引入完成,下面讲解控制器篇 191 // 最后的最后我们来回顾一下我们加载了些什么东西到程序中来 192 /* 193 * 1、ThinkPHP/Common/functions.php, // 标准模式函数库 194 * 2、ThinkPHP/Lib/Core/Log.class.php, // 日志处理类 195 * 3、ThinkPHP/Lib/Core/Dispatcher.class.php, // URL调度类 196 * 4、ThinkPHP/Lib/Core/App.class.php, // 应用程序类 197 * 5、ThinkPHP/Lib/Core/Action.class.php, // 控制器类 198 * 6、ThinkPHP/Lib/Core/View.class.php, // 视图类 199 * 7、ThinkPHP/Common/common.php //加载项目公共文件(函数库) 200 * 8、项目/Conf/alias.php 加载项目别名定义(项目自定义类库,用别名导入的方式引入的自定义类库) 201 * 9、ThinkPHP/Conf/debug.php的默认调试配置 202 */ 203 } 204 205 206 /* 207 * 加载了半天文件再在来真的了,正式进入程序运行 App::run(); 208 * /ThinkPHP/lib/Core/App.class.php //应用程序类 执行应用过程管理 209 * 这里是整个程序的入口,我们要跳着读,首先跳入App::init(); 210 * 最后一步跳入App::exec(); 211 */ 212 213 214 // #148-164 运行应用实例 入口文件使用的快捷方法 215 216 217 static public function run() { 218 // 项目初始化标签 219 tag(‘app_init‘); 220 App::init(); 221 // 项目开始标签 222 tag(‘app_begin‘); 223 // Session初始化 224 session(C(‘SESSION_OPTIONS‘)); 225 G(‘initTime‘); 226 //执行应用程序 227 App::exec(); 228 // 项目结束标签 229 tag(‘app_end‘); 230 // 保存日志记录 231 if(C(‘LOG_RECORD‘)) Log::save(); 232 return ; 233 } 234 235 236 // #36-76 应用程序初始化 237 static public function init() { 238 // load_ext_file(); 加载动态项目公共文件和配置 239 // URL调度 Dispatcher::dispatch(); //进入Thinkphp/lib/Core/Dispatcher.class.php dispatch()方法,进行URL参数常量赋值 240 // 如果有分组,include 分组配置与函数文件 241 // 获取模板主题名称 $templateSet = C(‘DEFAULT_THEME‘); 242 // 定义模板路径常量 define(‘THEME_PATH‘, TMPL_PATH.$group.(THEME_NAME?THEME_NAME.‘/‘:‘‘)); 243 // 定义模板路径常量 define(‘APP_TMPL_PATH‘,__ROOT__.‘/‘.APP_NAME.(APP_NAME?‘/‘:‘‘).basename(TMPL_PATH).‘/‘.$group.(THEME_NAME?THEME_NAME.‘/‘:‘‘)); 244 // 定义模板文件的位置 C(‘TEMPLATE_NAME‘,THEME_PATH.MODULE_NAME.(defined(‘GROUP_NAME‘)?C(‘TMPL_FILE_DEPR‘):‘/‘).ACTION_NAME.C(‘TMPL_TEMPLATE_SUFFIX‘)); 245 // 定义模板文件缓存的位置 C(‘CACHE_PATH‘,CACHE_PATH.$group); 246 } 247 248 249 // #89-138 执行应用程序 250 static public function exec() { 251 // 安全检测,模块名必须是英文和数字组成,且英文为首 252 // 检测通过 实例化 控制器 $module = A($group.MODULE_NAME); 253 // 检测如果定义了__hack_module()扩展,则遇到当前模块不存在时会被接管,优先级大于空模块EmptyAction 254 // 检测如果否定义空模块EmptyAction,则遇到不存在模块时调用EmptyAction模块 255 // 检测前置后置方法(_before_、_after_) method_exists($module,‘_before_‘.$action),如果有则执行 call_user_func(array(&$module,‘_before_‘.$action)); 256 // 亮点在这里,至此URL解析完成了,跳转到 某某模块下的某某方法 执行当前操作 call_user_func(array(&$module,$action)); 257 } 258 259 /* 260 * 接上一步,跳入App::init();后,我们发现需要跳入Dispatcher::dispatch();URL调度类中进行URL参数常量赋值,下面带你进入Disppatcher::dispatch方法中进行常量赋值 261 * ThinkPHP内置的Dispatcher类 只提供了一个公共的静态方法dispatch()方法作为接口,本方法将路由变量压入到常量中,供后面的action类使用 262 * 完成URL解析、路由和调度 263 * ThinkPHP/lib/Core/Dispatcher.class.php 264 * 完成后跳回到App::init(); 265 */ 266 267 268 //#36-153 URL映射到控制器 269 static public function dispatch() { 270 //C(‘URL_MODEL‘);读取URL模式 271 //将模块提取到MODULE_NAME全局变量中,将动作提取到ACTION_NAME全局变量中,将参数 272 // $paths = explode($depr,trim($_SERVER[‘PATH_INFO‘],‘/‘));//解析path_info 273 //$var[C(‘VAR_MODULE‘)] = array_shift($paths);//提取模块 274 // $var[C(‘VAR_ACTION‘)] = array_shift($paths);//提取方法 275 // $_GET = array_merge($var,$_GET);//重写$_GET 276 // pathinfo常量 __INFO__ 277 // 控制器常量 define(‘MODULE_NAME‘,self::getModule(C(‘VAR_MODULE‘))); 278 // 方法常量 define(‘ACTION_NAME‘,self::getAction(C(‘VAR_ACTION‘))); 279 // URL常量 define(‘__SELF__‘,strip_tags($_SERVER[‘REQUEST_URI‘])); 280 // 当前项目地址常量 define(‘__APP__‘,strip_tags(PHP_FILE)); 281 // 当前操作地址常量 define(‘__ACTION__‘,__URL__.$depr.ACTION_NAME); 282 // $_REQUEST = array_merge($_POST,$_GET); $_REQUEST重写 283 } 284 285 286 //注:获取系统配置用C()方法,此方法写得很巧妙,建议大家看一下
以上是关于ThinkPHP框架系统源码解析——URL路由解析的主要内容,如果未能解决你的问题,请参考以下文章
python 之 Django框架(路由系统include命名URL和URL反向解析命名空间模式)