runtime.php里的程序跑完后就加到了ThinkPHP.php里,ThinkPHP.php跑完后就加到了入口文件index.php里了。接下来印到眼前的是:
1 | App::run(); |
App就是框架的Core目录下的App.class.php,由上一节可以知道,在编译~runtime.php文件时它就被加载并编译到缓存里了。这个App可以理解为应用启动器。它有哪些东西呢?
init、build、exec、run这几个方法构成了这个“程序”的执行流程
getGroup、getModule、getAction获取分组名、模块名、操作名
appError、appException 自定义的错误处理和异常处理
checkLanguage、checkTemplate 语言检查、模板检查
程序是从run方法开始的,那就从它入手吧:
1 | static public function run() { |
它只是对init和exec的一个封装……而实际的启动是从init方法开始的:
定义错误和异常处理,把它们交给本类的appError和appException
编译项目缓存~app.php (在build方法里处理)
设置系统时区,注册autoload方法
URL路由 (这是框架里的重量级的东西,之后会单开一篇对它进行分析)
加载分组配置文件及模块配置文件(如果有的话)
语言检查、模板检查、开始静态缓存(取决于配置项HTML_CACHE_ON)
自定义错误和异常处理
1 | set_error_handler(array('App','appError')); |
把错误处理和异常处理交给App类里的appError方法和 appException。(这方面的内容可以参见:php错误处理 )
随便看一例:
1 | case E_USER_ERROR: |
E_USER_ERROR可以用php函数trigger_error来发出:
1 | trigger_error("这一条是测试信息", E_USER_ERROR); |
显示结果:
继续看init方法里的内容:
1 | if(defined('RUNTIME_MODEL')){ |
在这里见到了一位老朋友——RUNTIME_MODEL,如果是allinone模式的话,会定义这个常量。在这里剩下的部分也就省了。
如果不是的话,就要对~app.php进行判断:首先判断这个文件和项目配置文件config.php是否存在,之前检测缓存文件是否是最新的——通过filetime函数查询文件的时间来判断。然后根据判断的结果来进入相应的分支:直接读取缓存or重新生成缓存?
(这里先把init的流程走一遍,对于build方法的内容,放在下文解析)
1 | if(C('APP_PLUGIN_ON')) tag('app_begin'); |
分别根据配置来设置项目的开始标签、默认的时区、自动加载以及开启session。
1 | if(C('URL_DISPATCH_ON')) Dispatcher::dispatch(); |
如果配置里的URL路由打开了,就会执行URL路由。
1 | if(!defined('PHP_FILE')) |
对常量PHP_FILE的检查。
1 | if(C('APP_GROUP_LIST')) { |
加载分组配置文件和分组函数文件。我们可以专门针对分组来写配置文件和函数文件。格式分别是:
项目目录/Conf(配置目录)/分组名/config.php
项目目录/Common/分组名/config.php
1 | if(!defined('MODULE_NAME')) define('MODULE_NAME', App::getModule()); // Module名称 |
获取模块名和操作名。(在URL路由里处理,在exec方法里调用)
1 | if(is_file(CONFIG_PATH.strtolower(MODULE_NAME).'_config.php')) |
还可以为模块定义专用的配置文件,在此检测并加载。
1 | App::checkLanguage(); //语言检查 |
检测浏览器语言,加载语言包
检测模板主题
检测是否开启静态缓存
打开个标签。标签的介绍可以看2.1完全手册的6.2节《应用扩展》,这个功能在3.0里删除了。
init初始化完成,在进入exec之前,下节先把init里涉及到的一些方法和URL路由给通一通。^_^