上次回顾:
IS_WIN 看了一下后面的代码 基本上就是为了保证在不同环境下运行时,由于有些操作系统会对文件路径大小写敏感,定义该参数。对路径进行更严格的检查。
MAGIC_QUOTES_GPC :
1 if(version_compare(PHP_VERSION,'5.4.0','<')) { 2 ini_set('magic_quotes_runtime',0); 3 define('MAGIC_QUOTES_GPC',get_magic_quotes_gpc()? true : false); 4 }else{ 5 define('MAGIC_QUOTES_GPC',false); 6 }
如果PHP版本为小于5.4的时候 则进行把 magic_quotes_runtime 功能进行关闭 。对于大于5.4版本的PHP默认情况下是关闭的。
为什么要关闭呢?个人的理解是,如果该功能打开的话,我们给服务器传值的时候遇到单引号双引号斜杠的时候会在加上一个斜杠,这个会对路由识别的时候照成很大的影响。不利于路由的解析。同时如果你传入的数据要对数据库进行草的时候,如果存在上述字符的时候,会多加上一个斜杠。
IS_CGI和IS_CLI
关于这两个参数,我目前还明白,只知道和php和apache运行的时候有关。
本次目标:
对ThinkPHP\Library\Think\Think.clas.php的start进行说明
1 // 注册AUTOLOAD方法 2 spl_autoload_register('Think\Think::autoload'); 3 // 设定错误和异常处理 4 register_shutdown_function('Think\Think::fatalError'); 5 set_error_handler('Think\Think::appError'); 6 set_exception_handler('Think\Think::appException'); 7 // 初始化文件存储方式 8 Storage::connect(STORAGE_TYPE);
利用spl_autoload_register 函数进行注册,目的是以后如果实例某个类时,而该类并不已经被加载的文件中时候,调用注册的函数 autoload。所以该在后面所以的代码中,如果该类并没有被加载过时,通过该该方法进行把类实例化。
至于为什么能成功实例化呢?在TP中我们的我的类都有一定的命名规则 例如 $User = new \Home\Model\UserModel();
我们可以发现其中的规则,Home是我们的模块名称。Model为模块下模型的文件夹,UserModel
才是我们真正的需要实例化的模型类,而autoload方法加载的大致流程就是这样(注意我说的是大致,如果你去看autoload代码,其中还是对某系文件进行了特殊的照顾),autoload找到我们的模块文件,并找到我们的模型类文件夹,然后在去找到我们要的模型类。
而后面的三行代码则是对程序中出现了异常进行调用的方法。他可以帮我记录错误日子,帮我们美化错误页面。
最后一行代码则是初始化TP中对文件进行删除,写入、加载等操作的类。
至于为什么一个Storage就能找到文件夹处理的类呢?Storage也是通过autoload函数才能找到该类,而Storage就是我们说的被autoload函数特殊照顾的类。autoload函数收到如果加载Storage时,对去找到Storage存放的文件位置。
1 $runtimefile = RUNTIME_PATH.APP_MODE.'~runtime.php'; 2 if(!APP_DEBUG && Storage::has($runtimefile)){ 3 Storage::load($runtimefile); 4 }else{ 5 if(Storage::has($runtimefile)) 6 Storage::unlink($runtimefile); //删除文件 7 $content = ''; 8 // 读取应用模式 如果aplication\common\conf\core.php 存在 则读取,不存在这读取Thinkphp\Mode\common。php 9 $mode = include is_file(CONF_PATH.'core.php')?CONF_PATH.'core.php':MODE_PATH.APP_MODE.'.php'; 10 // 加载核心文件 11 18 // 加载应用模式配置文件 load_config 会根据文件的后缀名进行调用对于的文件进行加载 并且利用C函数进行配置的设置 22 23 // 读取当前应用模式对应的配置文件 判断是否是新浪SEA 如果是新浪的SEA 那么APP_MODE为SEA 否则是common 24 27 // 加载模式别名定义 28 32 // 加载应用别名定义文件 CONF_PATH= appliction\common\conf 33 36 // 加载模式行为定义 37 41 // 加载应用行为定义 42 46 // 加载框架底层语言包 THINK_PATH=thinphp C('DEFAULT_LANG')=zh-cn 47 49 if(!APP_DEBUG){ 50 $content .= "\nnamespace { Think\\Think::addMap(".var_export(self::$_map,true).");"; 51 $content .= "\nL(".var_export(L(),true).");\nC(".var_export(C(),true).');Think\Hook::import('.var_export(Hook::get(),true).');}'; 52 Storage::put($runtimefile,strip_whitespace('<?php '.$content)); 53 }else{ 54 // 调试模式加载系统默认的配置文件 55 C(include THINK_PATH.'Conf/debug.php'); 56 // 读取应用调试配置文件 57 if(is_file(CONF_PATH.'debug'.CONF_EXT)) 58 C(include CONF_PATH.'debug'.CONF_EXT); 59 } 60 }
接下来运行的代码(把其中的一些部分进行删除),第一行
1 $runtimefile = RUNTIME_PATH.APP_MODE.'~runtime.php';
定义编译文件的路径,应该程序比较死嘛,所以如果存在编译过的文件,那么他的路径也是一定的。那么这个文件有什么用呢?集体的说就是else下面的把很多配置文件include进来都保存到该文下,可能也有一些后面的文件中的代码。基本就是我把正常运行情况下那些不变的代码保存到该文件中,那么我下次直接加载这个文件,我就不需要一次次的去反复IO操作读取那么文件,提高框架的效率。
而else中的代码则是把个各种配置文件加载到框架中(注意是配置文件,例如别名配置文件,他会按照数组的形式报错其中,key是别名,value则是路径)
1 // 加载应用模式配置文件 load_config 会根据文件的后缀名进行调用对于的文件进行加载 并且利用C函数进行配置的设置 2 foreach ($mode['config'] as $key=>$file){ 3 is_numeric($key)?C(load_config($file)):C($key,load_config($file)); 4 }
该行对对C函数进行初始化赋值,利用Thinkphp\Mode\common.php下的config数组中的目录进行加载配置。从此C函数就有很很多的配置文件信息了。我就可以通过C函数进行查询。同样别和模型行为也是相同的原理
1 // 加载应用行为定义 2 if(is_file(CONF_PATH.'tags.php')) 3 // 允许应用增加开发模式配置定义 4 Hook::import(include CONF_PATH.'tags.php');
如用户存在aplication\common\conf\tags.php的行为定义,那么加载他到全局的行为定义模版中。那样用户的行为定义就可以在全局调用。
1 // 加载框架底层语言包 THINK_PATH=thinphp C('DEFAULT_LANG')=zh-cn
2 L(include THINK_PATH.'Lang/'.strtolower(C('DEFAULT_LANG')).'.php');
定义语音包(说来惭愧,应为重来没有用过,所以也没如何去了解,这里就不说太多),配置文件中DEFAULT_LANG定义是zh-cn
1 if(!APP_DEBUG){ 2 $content .= "\nnamespace { Think\\Think::addMap(".var_export(self::$_map,true).");"; 3 $content .= "\nL(".var_export(L(),true).");\nC(".var_export(C(),true).');Think\Hook::import('.var_export(Hook::get(),true).');}'; 4 Storage::put($runtimefile,strip_whitespace('<?php '.$content)); 5 }else{ 6 // 调试模式加载系统默认的配置文件 7 C(include THINK_PATH.'Conf/debug.php'); 8 // 读取应用调试配置文件 9 if(is_file(CONF_PATH.'debug'.CONF_EXT)) 10 C(include CONF_PATH.'debug'.CONF_EXT); 11 }
如果不再debug模式下面,那么会把上面的配置文件信息数组取下来,报错到编译的文件下面,如果在debug模式下面,那么会去加载debug配置文件信息到C函数下,方便我们进行调试。
1 // 读取当前应用状态对应的配置文件 如果配置了状态文件,那么加载到其中 2 if(APP_STATUS && is_file(CONF_PATH.APP_STATUS.CONF_EXT)) 3 C(include CONF_PATH.APP_STATUS.CONF_EXT); 4 5 // 设置系统时区 6 date_default_timezone_set(C('DEFAULT_TIMEZONE')); 7 8 // 检查应用目录结构 如果不存在则自动创建 如果信息观察刚下载下来的目录时候,我们会发现 Application里面是没有多余的文件夹的,这这个时候,
该方法就实现了创建出默认的分组 9 if(C('CHECK_APP_DIR')) { 10 $module = defined('BIND_MODULE') ? BIND_MODULE : C('DEFAULT_MODULE'); 11 if(!is_dir(APP_PATH.$module) || !is_dir(LOG_PATH)){ 12 // 检测应用目录结构 13 Build::checkDir($module); 14 } 15 } 16 17 // 记录加载文件时间 18 G('loadTime'); 19 // 运行应用 20 App::run(); //app作为核心类 在52行被加载进入 后面将会开始路由,模版加载等一些了操作
总结:
这主要还是对配置文件进行各种初始化,特别是C函数,应该这个函数我们后面会经常碰到。
这里我们发现TP给我们提供了对C函数进行个性化配置的设置,
一个是如果存在aplication\common\conf\core.php 那么它将优于Thinkphp\Mode\common.php被加载
如果我们定义了状态文件配置,那么它会去加载状态文件配置信息