利用xdebug和netbeans调试thinkphp源码及流程分析

来源:互联网 发布:免费的招聘软件 编辑:程序博客网 时间:2024/05/16 04:46
这周活比较轻松,正好过一遍thinkphp源码(3.1.2版),弄清楚该框架内部实现的流程,增长些知识。


第一步,安装xdebug,写个测试页,里面写上phpinfo();把内容复制贴到http://www.xdebug.org/find-binary.php页面里,点击提交,之后会提示本机php对应的xdebug版本,下载后放到php目录下的ext目录内,再把下面的配置写入php.ini内,之后重启apache服务器,再刷新测试页面,看界面上是否有xdebug字样。

[php] view plaincopy
  1. zend_extension="D:\server\php\php-5.3.8-Win32-VC9-x86\ext\php_xdebug-2.1.4-5.3-vc9.dll"  
  2.   
  3. [Xdebug]  
  4.   
  5. ;是否开启自动跟踪  
  6. xdebug.auto_trace = On  
  7. ;是否开启异常跟踪  
  8. xdebug.show_exception_trace = On  
  9. ;是否开启远程调试自动启动  
  10. xdebug.remote_autostart = On  
  11. ;是否开启远程调试  
  12. xdebug.remote_enable = On  
  13. ;允许调试的客户端IP  
  14.   
  15. ;远程调试的端口(默认9000)  
  16. xdebug.remote_port=9001  
  17. ;调试插件dbgp  
  18. xdebug.remote_handler=dbgp  
  19. ;是否收集变量  
  20. xdebug.collect_vars = On  
  21. ;是否收集返回值  
  22. xdebug.collect_return = On  
  23. ;是否收集参数  
  24. xdebug.collect_params = On  
  25. ;跟踪输出路径  
  26. xdebug.trace_output_dir="c:\xdebug"  
  27. ;是否开启调试内容  
  28. xdebug.profiler_enable=On  
  29. ;调试输出路径  
  30. xdebug.profiler_output_dir="c:\xdebug"  
  31. xdebug.remote_host=localhost  



第二步,打开netbeans,在工具-选项-php-调试框内,把调试器端口写成和php.ini内xdebug.remote_port一致,点击应用-确定。



第三步,新建项目,也就是把thinkphp创建的项目导入进去,进入项目内,点击调试项目,之后会弹出一个会话框,在项目URL和索引文件填入正确的信息,之后便可以调试了。



第四步,开始调试。进入项目的一个具体页面,点击调试文件或是调试项目,之后调试便开始了,按F7键进行调试。下面,我便把调试后的的心得写下来。


1) 由于thinkphp是单入口的文件,因此调试界面首先便跳到index.php中,该页面主要负责定义项目名称、项目路径、thinkphp所在路径、是否开启调试模式,之后便引入ThinkPHP.php。


2)在ThinkPHP.php页面里,主要是定义了项目开始运行时间、开始时的内存使用情况、重新检测了是否定义项目路径、缓存目录路径、项目是否开始调试模式、~runtime.php存放地址,若是项目开启调试,则进入THINK_PATH.'Common/runtime.php',没有开启则直接进入已编译好的~runtime.php.,这里属于调试模式,即APP_DEBUG为TRUE。


3)runtime.php文件主要负责检测是否定义thinkphp路径,没有的话就退出,这应该是阻止恶意链接吧,定义版本信息,检测php的版本,定义系统常量、URL的4种模式、目录常量(tp系统的和项目的),加载运行所需文件,记录加载文件文件时间,执行Think::Start()。这里着重解释下load_runtime_file()函数。

[php] view plaincopy
  1. // 加载运行时所需要的文件 并负责自动目录生成  
  2. function load_runtime_file() {  
  3.   
  4.     // 加载系统基础函数库  
  5.     // require_cache函数所在文件,要先引入,才能正确执行  
  6.     require THINK_PATH.'Common/common.php';  
  7.   
  8.     // 读取核心文件列表  
  9.     // 因为接下来便是进入Think.class.php文件,因此要引入该文件  
  10.     // 同时由于在执行过程中可能会遇到错误或是异常,便引入ThinkException.class.php异常处理类  
  11.     // 在App::run()方法内会执行tag函数,会用Behavior.class.php类,于是也被一同引入  
  12.     $list = array(  
  13.         CORE_PATH.'Core/Think.class.php',  
  14.         CORE_PATH.'Core/ThinkException.class.php',  // 异常处理类  
  15.         CORE_PATH.'Core/Behavior.class.php',  
  16.     );  
  17.   
  18.     // 加载模式文件列表  
  19.     foreach ($list as $key=>$file){  
  20.   
  21.         // require_cache 可以看成是一个优化的require方法  
  22.         // 实际上是引入了static静态变量,避免文件重复引入  
  23.         // 在thinkphp中static的思维贯穿其中  
  24.         if(is_file($file))  require_cache($file);  
  25.     }  
  26.   
  27.     // 加载系统类库别名定义  
  28.     //alias_import(include THINK_PATH.'Conf/alias.php');  
  29.   
  30.     // 检查项目目录结构 如果不存在则自动创建  
  31.     if(!is_dir(LIB_PATH)) {  
  32.   
  33.         // 创建项目目录结构  
  34.         build_app_dir();  
  35.     }elseif(!is_dir(CACHE_PATH)){  
  36.   
  37.         // 检查缓存目录  
  38.         check_runtime();  
  39.     }elseif(APP_DEBUG){  
  40.   
  41.         // 调试模式切换删除编译缓存  
  42.         if(is_file(RUNTIME_FILE))   unlink(RUNTIME_FILE);  
  43.     }  
  44. }  


4)进入Thinkphp,执行静态方法Start(),该方法重新定义了异常、错误、自动加载机制,执行Think::buildApp()方法

a)Think::buildApp()方法主要实现了thinkphp官方手册中的“惯例配置->项目配置->调试配置->分组配置->扩展配置->动态配置”说明。

[php] view plaincopy
  1. // 加载底层惯例配置文件  
  2. C(include THINK_PATH.'Conf/convention.php');  
  3. C(include THINK_PATH.'Conf/config.php');  
  4.   
  5. // 加载项目配置文件  
  6. C(include CONF_PATH.'config.php');  
  7.   
  8. // 加载框架底层语言包  
  9. L(include THINK_PATH.'Lang/'.strtolower(C('DEFAULT_LANG')).'.php');  
  10.   
  11. // 默认加载系统行为扩展定义  
  12. C('extends'include THINK_PATH.'Conf/tags.php');  
  13.   
  14. // 默认加载项目配置目录的tags文件定义  
  15. C('tags'include CONF_PATH.'tags.php');  
  16.   
  17. THINK_PATH.'Common/functions.php'// 标准模式函数库  
  18. CORE_PATH.'Core/Log.class.php',    // 日志处理类  
  19. CORE_PATH.'Core/Dispatcher.class.php'// URL调度类  
  20. CORE_PATH.'Core/App.class.php',   // 应用程序类  
  21. CORE_PATH.'Core/Action.class.php'// 控制器类  
  22. CORE_PATH.'Core/View.class.php',  // 视图类  
  23.   
  24. // 加载项目公共文件  
  25. include COMMON_PATH.'common.php';  
  26.   
  27. // 加载系统别名文件,这里主要在tag函数中利用到  
  28. include THINK_PATH.'Conf/alias.php';  
  29.   
  30. // 加载项目别名文件,如果有的话,若是项目中配置了,可以在项目中的Behavior目录里写相关的行为代码  
  31. include CONF_PATH.'alias.php';  
  32.   
  33. // 调试模式加载系统默认的配置文件  
  34. C(include THINK_PATH.'Conf/debug.php');  
  35.   
  36. // 加载对应的项目配置文件   
  37. C( include CONF_PATH . C('APP_STATUS') . '.php');  


5)上述方法执行完后,进入App.class.php中执行App::run()方法。

a)tag('app_init'),项目初始化标签,在tag.php文件中可以看到,app_init对应的值为空,因此这个标签是什么也没执行。之后在第九条详细解释tag方法。


6)执行App::init()方法,该方法首先设置时区,默认为PRC,可以通过在项目中配置DEFAULT_TIMEZONE的值来修改,之后加载动态项目公共文件和配置

a)load_ext_file()方法主要是加载动态扩展文件

[php] view plaincopy
  1. /** 
  2.  * 加载动态扩展文件 
  3.  * @return void 
  4.  */  
  5. function load_ext_file() {  
  6.   
  7.     // 通过在项目里配置LOAD_EXT_FILE、LOAD_EXT_CONFIG来动态加载文件  
  8.   
  9.     // 加载自定义外部文件  
  10.     // LOAD_EXT_FILE => 'guest,user';  
  11.     // 那么便会加载项目公共目录(Common)内的guest.php和user.php文件  
  12.     if (C('LOAD_EXT_FILE')) {  
  13.         $files = explode(',', C('LOAD_EXT_FILE'));  
  14.         foreach ($files as $file) {  
  15.             $file = COMMON_PATH . $file . '.php';  
  16.             if (is_file($file))  
  17.                 include $file;  
  18.         }  
  19.     }  
  20.   
  21.     // 加载自定义的动态配置文件  
  22.     // LOAD_EXT_CONFIG => 'guest,user';  
  23.     // 那么便会加载项目配置(Conf)目录内的guest.php和user.php文件  
  24.     if (C('LOAD_EXT_CONFIG')) {  
  25.         $configs = C('LOAD_EXT_CONFIG');  
  26.         if (is_string($configs))  
  27.             $configs = explode(','$configs);  
  28.         foreach ($configs as $key => $config) {  
  29.             $file = CONF_PATH . $config . '.php';  
  30.             if (is_file($file)) {  
  31.                 is_numeric($key) ? C(include $file) : C($keyinclude $file);  
  32.             }  
  33.         }  
  34.     }  
  35.   
  36.     // 加载不同的操作系统下的配置  
  37.     // 以便在不同操作系统执行工具的不同平台的版本  
  38.     if (C('OS_CONFIG')) {  
  39.         if (preg_match('/WIN/', PHP_OS)) {  
  40.             $file = CONF_PATH . 'win.php';  
  41.         } else {  
  42.             $file = CONF_PATH . 'linux.php';  
  43.         }  
  44.         if (is_file($file))  
  45.             C(include $file);  
  46.     }  
  47. }  


7)进入Dispatcher.class.php执行Dispatcher::dispatch()方法。

[php] view plaincopy
  1. /** 
  2.  * URL映射到控制器 
  3.  * @access public 
  4.  * @return void 
  5.  */  
  6. static public function dispatch() {  
  7.   
  8.     // 项目的URL_MODEL为2,也就是define('URL_REWRITE',     2)即REWRITE模式  
  9.     $urlMode  =  C('URL_MODEL');  
  10.   
  11.     // 判断URL里面是否有兼容模式参数  
  12.     // VAR_PATHINFO的值为s  
  13.     // 这时$_GET没有接收到参数,而且即使有,参数中也没有s的  
  14.     if(!empty($_GET[C('VAR_PATHINFO')])) {  
  15.         $_SERVER['PATH_INFO']   = $_GET[C('VAR_PATHINFO')];  
  16.         unset($_GET[C('VAR_PATHINFO')]);  
  17.     }  
  18.   
  19.     // 条件不符  
  20.     if($urlMode == URL_COMPAT ){  
  21.   
  22.         // 兼容模式判断  
  23.         define('PHP_FILE',_PHP_FILE_.'?'.C('VAR_PATHINFO').'=');  
  24.   
  25.     // URL_REWRITE在runtime中的定义为2  
  26.     // 条件符合,定义PHP_FILE常量  
  27.     }elseif($urlMode == URL_REWRITE ) {  
  28.   
  29.         // 当前项目地址  
  30.         $url    =   dirname(_PHP_FILE_);  
  31.         if($url == '/' || $url == '\\')  
  32.             $url    =   '';  
  33.         define('PHP_FILE',$url);  
  34.   
  35.     // 条件不符  
  36.     }else {  
  37.   
  38.         //当前项目地址  
  39.         define('PHP_FILE',_PHP_FILE_);  
  40.     }  
  41.   
  42.     // 项目没有开启子域名  
  43.     // 开启子域名部署  
  44.     if(C('APP_SUB_DOMAIN_DEPLOY')) {  
  45.         $rules      = C('APP_SUB_DOMAIN_RULES');  
  46.         $subDomain  = strtolower(substr($_SERVER['HTTP_HOST'],0,strpos($_SERVER['HTTP_HOST'],'.')));  
  47.         define('SUB_DOMAIN',$subDomain); // 二级域名定义  
  48.         if($subDomain && isset($rules[$subDomain])) {  
  49.             $rule =  $rules[$subDomain];  
  50.         }elseif(isset($rules['*'])){ // 泛域名支持  
  51.             if('www' != $subDomain && !in_array($subDomain,C('APP_SUB_DOMAIN_DENY'))) {  
  52.                 $rule =  $rules['*'];  
  53.             }  
  54.         }  
  55.         if(!empty($rule)) {  
  56.             // 子域名部署规则 '子域名'=>array('分组名/[模块名]','var1=a&var2=b');  
  57.             $array  =   explode('/',$rule[0]);  
  58.             $module =   array_pop($array);  
  59.             if(!empty($module)) {  
  60.                 $_GET[C('VAR_MODULE')]  =   $module;  
  61.                 $domainModule           =   true;  
  62.             }  
  63.             if(!empty($array)) {  
  64.                 $_GET[C('VAR_GROUP')]   =   array_pop($array);  
  65.                 $domainGroup            =   true;  
  66.             }  
  67.             if(isset($rule[1])) { // 传入参数  
  68.                 parse_str($rule[1],$parms);  
  69.                 $_GET   =  array_merge($_GET,$parms);  
  70.             }  
  71.         }  
  72.     }  
  73.   
  74.     // 该变量的值不为空,因此条件不成立  
  75.     // 分析PATHINFO信息  
  76.     if(empty($_SERVER['PATH_INFO'])) {  
  77.         $types   =  explode(',',C('URL_PATHINFO_FETCH'));  
  78.         foreach ($types as $type){  
  79.             if(0===strpos($type,':')) {// 支持函数判断  
  80.                 $_SERVER['PATH_INFO'] =   call_user_func(substr($type,1));  
  81.                 break;  
  82.             }elseif(!empty($_SERVER[$type])) {  
  83.                 $_SERVER['PATH_INFO'] = (0 === strpos($_SERVER[$type],$_SERVER['SCRIPT_NAME']))?  
  84.                     substr($_SERVER[$type], strlen($_SERVER['SCRIPT_NAME']))   :  $_SERVER[$type];  
  85.                 break;  
  86.             }  
  87.         }  
  88.     }  
  89.   
  90.     // 分割符为/  
  91.     $depr = C('URL_PATHINFO_DEPR');  
  92.   
  93.     if(!empty($_SERVER['PATH_INFO'])) {  
  94.   
  95.         // 在tags.php中path_info的值为空,因此这里不执行操作  
  96.         tag('path_info');  
  97.   
  98.         // 拆分PATH_INFO,具体的可以参照手册中pathinfo函数  
  99.         $part =  pathinfo($_SERVER['PATH_INFO']);  
  100.   
  101.         // 定义__EXT__常量  
  102.         define('__EXT__', isset($part['extension'])?strtolower($part['extension']):'');  
  103.         if(C('URL_HTML_SUFFIX')) {  
  104.             $_SERVER['PATH_INFO'] = preg_replace('/\.('.trim(C('URL_HTML_SUFFIX'),'.').')$/i'''$_SERVER['PATH_INFO']);  
  105.         }elseif(__EXT__) {  
  106.             $_SERVER['PATH_INFO'] = preg_replace('/.'.__EXT__.'$/i','',$_SERVER['PATH_INFO']);  
  107.         }  
  108.   
  109.         // 由于项目中没有采用路由规则,因此条件成立  
  110.         // 检测路由规则 如果没有则按默认规则调度URL  
  111.         if(!self::routerCheck()){  
  112.   
  113.             // 拆分$_SERVER['PATH_INFO']为数组  
  114.             $paths = explode($depr,trim($_SERVER['PATH_INFO'],'/'));  
  115.   
  116.             // VAR_URL_PARAMS值为_URL_  
  117.             if(C('VAR_URL_PARAMS')) {  
  118.   
  119.                 // 把$_SERVER['PATH_INFO']的按/分割成数组,并赋值给$_GET的_URL_变量  
  120.                 $_GET[C('VAR_URL_PARAMS')]   =  $paths;  
  121.             }  
  122.   
  123.             $var  =  array();  
  124.   
  125.             // APP_GROUP_LIST为项目中设置的组  
  126.             // VAR_GROUP置为g,由于$_GET没有接收此参数,因此条件成立  
  127.             if (C('APP_GROUP_LIST') && !isset($_GET[C('VAR_GROUP')])){  
  128.                 $var[C('VAR_GROUP')] = in_array(strtolower($paths[0]),explode(',',strtolower(C('APP_GROUP_LIST'))))? array_shift($paths) : '';  
  129.                 if(C('APP_GROUP_DENY') && in_array(strtolower($var[C('VAR_GROUP')]),explode(',',strtolower(C('APP_GROUP_DENY'))))) {  
  130.                     // 禁止直接访问分组  
  131.                     exit;  
  132.                 }  
  133.             }  
  134.   
  135.             // 还没有定义模块名称  
  136.             if(!isset($_GET[C('VAR_MODULE')])) {  
  137.                 $var[C('VAR_MODULE')]  =   array_shift($paths);  
  138.             }  
  139.             $var[C('VAR_ACTION')]  =   array_shift($paths);  
  140.   
  141.             // 解析剩余的URL参数  
  142.             preg_replace('@(\w+)\/([^\/]+)@e''$var[\'\\1\']=strip_tags(\'\\2\');', implode('/',$paths));  
  143.   
  144.             // 把$var和$_GET合并形成新的$_GET数组,这时URL映射基本完整  
  145.             $_GET   =  array_merge($var,$_GET);  
  146.         }  
  147.         define('__INFO__',$_SERVER['PATH_INFO']);  
  148.     }  
  149.   
  150.     // URL常量  
  151.     define('__SELF__',strip_tags($_SERVER['REQUEST_URI']));  
  152.   
  153.     // 当前项目地址  
  154.     define('__APP__',strip_tags(PHP_FILE));  
  155.   
  156.     // 获取分组 模块和操作名称  
  157.     if (C('APP_GROUP_LIST')) {  
  158.   
  159.         // 默认分组为Home,这里主要依据当前访问的文件的位置  
  160.         // 如果文件为Home分组下就是Home  
  161.         define('GROUP_NAME', self::getGroup(C('VAR_GROUP')));  
  162.   
  163.         // 分组URL地址  
  164.         define('__GROUP__',(!empty($domainGroup) || strtolower(GROUP_NAME) == strtolower(C('DEFAULT_GROUP')) )?__APP__ : __APP__.'/'.GROUP_NAME);  
  165.     }  
  166.   
  167.     // 定义项目基础加载路径  
  168.     define('BASE_LIB_PATH', (defined('GROUP_NAME') && C('APP_GROUP_MODE')==1) ? APP_PATH.C('APP_GROUP_PATH').'/'.GROUP_NAME.'/' : LIB_PATH);  
  169.     if(defined('GROUP_NAME')) {  
  170.         if(1 == C('APP_GROUP_MODE')){ // 独立分组模式  
  171.             $config_path    =   BASE_LIB_PATH.'Conf/';  
  172.             $common_path    =   BASE_LIB_PATH.'Common/';  
  173.         }else// 普通分组模式  
  174.             $config_path    =   CONF_PATH.GROUP_NAME.'/';  
  175.             $common_path    =   COMMON_PATH.GROUP_NAME.'/';  
  176.         }  
  177.   
  178.         // 加载分组配置文件  
  179.         if(is_file($config_path.'config.php'))  
  180.             C(include $config_path.'config.php');  
  181.   
  182.         // 加载分组函数文件  
  183.         if(is_file($common_path.'function.php'))  
  184.             include $common_path.'function.php';  
  185.     }  
  186.   
  187.     // 定义模块名和方法名常量  
  188.     define('MODULE_NAME',self::getModule(C('VAR_MODULE')));  
  189.     define('ACTION_NAME',self::getAction(C('VAR_ACTION')));  
  190.   
  191.     // 当前模块和分组地址  
  192.     $moduleName    =   defined('MODULE_ALIAS')?MODULE_ALIAS:MODULE_NAME;  
  193.     if(defined('GROUP_NAME')) {  
  194.         define('__URL__',!empty($domainModule)?__GROUP__.$depr : __GROUP__.$depr.$moduleName);  
  195.     }else{  
  196.         define('__URL__',!empty($domainModule)?__APP__.'/' : __APP__.'/'.$moduleName);  
  197.     }  
  198.     $tmpAppUrl = explode('/', __URL__);  
  199.   
  200.     //define('__APPURL__', '/' . $tmpAppUrl[1] . '/' . $tmpAppUrl[2]);  
  201.     define('__APPURL__''./');  
  202.   
  203.     // 当前操作地址  
  204.     define('__ACTION__',__URL__.$depr.(defined('ACTION_ALIAS')?ACTION_ALIAS:ACTION_NAME));  
  205.   
  206.     //保证$_REQUEST正常取值  
  207.     $_REQUEST = array_merge($_POST,$_GET);  
  208. }  

8)回到App::init()方法,定义当前请求的系统常量、URL调度结束、页面压缩输出支持、系统变量安全过滤(过滤$_GET、$_POST)、设置模板相关信息、动态配置异常界面(若是觉得tp异常界面不友好的话,可以重新设计下界面,并在放在项目目录内,在配置文件内通过TMPL_EXCEPTION_FILE来设定)


9)回到App::run()方法,执行tag('app_begin')方法,这里详细介绍下tag方法执行机制

[php] view plaincopy
  1. /** 
  2.  * 处理标签扩展 
  3.  * @param string $tag 标签名称 
  4.  * @param mixed $params 传入参数 
  5.  * @return mixed 
  6.  */  
  7. function tag($tag, &$params=NULL) {  
  8.   
  9.     // 这里$tag的值为app_begin  
  10.     // 因为在Think.class.php文件中的静态方法buildapp()中已经将tags.php中  
  11.     // 关于行为的值赋值给extends键,通过查看文件可知这里的app_begin是有值的  
  12.     // 值为ReadHtmlCache  
  13.   
  14.     // 系统标签扩展  
  15.     $extends    = C('extends.' . $tag);  
  16.   
  17.     // 应用标签扩展  
  18.     $tags       = C('tags.' . $tag);  
  19.   
  20.     // $tags这里没有值,条件不成立  
  21.     if (!empty($tags)) {  
  22.   
  23.         // 合并扩展  
  24.         if(empty($tags['_overlay']) && !empty($extends)) {  
  25.             $tags = array_unique(array_merge($extends,$tags));  
  26.   
  27.         // 通过设置 '_overlay'=>1 覆盖系统标签  
  28.         } elseif (isset($tags['_overlay'])){  
  29.             unset($tags['_overlay']);  
  30.         }  
  31.   
  32.     // 把extends的值赋给$tags  
  33.     } elseif (!empty($extends)) {  
  34.         $tags = $extends;  
  35.     }  
  36.   
  37.     if($tags) {  
  38.   
  39.         if(APP_DEBUG) {  
  40.             G($tag.'Start');  
  41.             trace('[ '.$tag.' ] --START--','','INFO');  
  42.         }  
  43.   
  44.         // 执行扩展  
  45.         foreach ($tags as $key=>$name) {  
  46.   
  47.             // 指定行为类的完整路径 用于模式扩展  
  48.             if(!is_int($key)) {  
  49.                 $name   = $key;  
  50.             }  
  51.   
  52.             // 执行B方法  
  53.             B($name$params);  
  54.         }  
  55.   
  56.         // 记录行为的执行日志  
  57.         if(APP_DEBUG) {  
  58.             trace('[ '.$tag.' ] --END-- [ RunTime:'.G($tag.'Start',$tag.'End',6).'s ]','','INFO');  
  59.         }  
  60.   
  61.     // 未执行任何行为 返回false  
  62.     } else {  
  63.         return false;  
  64.     }  
  65. }  
  66.   
  67. /** 
  68.  * 执行某个行为 
  69.  * @param string $name 行为名称 
  70.  * @param Mixed $params 传人的参数 
  71.  * @return void 
  72.  */  
  73. function B($name, &$params=NULL) {  
  74.   
  75.     // 把ReadHtmlCache的值传过来,并重新组合为ReadHtmlCacheBehavior  
  76.     $class      = $name.'Behavior';  
  77.     if(APP_DEBUG) {  
  78.         G('behaviorStart');  
  79.     }  
  80.   
  81.     // 执行ReadHtmlCacheBehavior类,这里就用到了前面的thinkphp自定义的autoload方法  
  82.     // 因为ReadHtmlCacheBehavior.class.php没有加载进来,因此在new之前要加载进来  
  83.     // 加载后执行实例化操作,由于ReadHtmlCacheBehavior都是继承Behavior类,因此在实例化时  
  84.     // 也自动执行了析构函数__construct,该函数类似C方法  
  85.     $behavior   = new $class();  
  86.   
  87.     // 执行ReadHtmlCacheBehavior类的run方法,因为没有设定HTML_CACHE_RULES,因此下面是不执行操作的  
  88.     $behavior->run($params);  
  89.     if(APP_DEBUG) { // 记录行为的执行日志  
  90.         G('behaviorEnd');  
  91.         trace('Run '.$name.' Behavior [ RunTime:'.G('behaviorStart','behaviorEnd',6).'s ]','','INFO');  
  92.     }  
  93. }  
  94.   
  95. /** 
  96.  * 系统自动加载ThinkPHP类库 
  97.  * 并且支持配置自动加载路径 
  98.  * @param string $class 对象类名 
  99.  * @return void 
  100.  */  
  101. public static function autoload($class) {  
  102.   
  103.     // 检查是否存在别名定义  
  104.     if(alias_import($class)) return ;  
  105.     $libPath    =   defined('BASE_LIB_PATH')?BASE_LIB_PATH:LIB_PATH;  
  106.     $group      =   defined('GROUP_NAME') && C('APP_GROUP_MODE')==0 ?GROUP_NAME.'/':'';  
  107.   
  108.     // 这里的$file变成了ReadHtmlCacheBehavior.class.php  
  109.     $file       =   $class.'.class.php';  
  110.   
  111.     // 加载行为,此条件成立,这里加载多个行为,系统核心的、系统扩展的、项目自身的(后面两个时一样的)  
  112.     // 加载完后变返回  
  113.     if(substr($class,-8)=='Behavior') {  
  114.         if(require_array(array(  
  115.             CORE_PATH.'Behavior/'.$file,  
  116.             EXTEND_PATH.'Behavior/'.$file,  
  117.             LIB_PATH.'Behavior/'.$file,  
  118.             $libPath.'Behavior/'.$file),true)  
  119.             || (defined('MODE_NAME') && require_cache(MODE_PATH.ucwords(MODE_NAME).'/Behavior/'.$file))) {  
  120.             return ;  
  121.         }  
  122.     }elseif(substr($class,-5)=='Model'){ // 加载模型  
  123.         if(require_array(array(  
  124.             LIB_PATH.'Model/'.$group.$file,  
  125.             $libPath.'Model/'.$file,  
  126.             EXTEND_PATH.'Model/'.$file),true)) {  
  127.             return ;  
  128.         }  
  129.     }elseif(substr($class,-6)=='Action'){ // 加载控制器  
  130.         if(require_array(array(  
  131.             LIB_PATH.'Action/'.$group.$file,  
  132.             $libPath.'Action/'.$file,  
  133.             EXTEND_PATH.'Action/'.$file),true)) {  
  134.             return ;  
  135.         }  
  136.     }elseif(substr($class,0,5)=='Cache'){ // 加载缓存驱动  
  137.         if(require_array(array(  
  138.             EXTEND_PATH.'Driver/Cache/'.$file,  
  139.             CORE_PATH.'Driver/Cache/'.$file),true)){  
  140.             return ;  
  141.         }  
  142.     }elseif(substr($class,0,2)=='Db'){ // 加载数据库驱动  
  143.         if(require_array(array(  
  144.             EXTEND_PATH.'Driver/Db/'.$file,  
  145.             CORE_PATH.'Driver/Db/'.$file),true)){  
  146.             return ;  
  147.         }  
  148.     }elseif(substr($class,0,8)=='Template'){ // 加载模板引擎驱动  
  149.         if(require_array(array(  
  150.             EXTEND_PATH.'Driver/Template/'.$file,  
  151.             CORE_PATH.'Driver/Template/'.$file),true)){  
  152.             return ;  
  153.         }  
  154.     }elseif(substr($class,0,6)=='TagLib'){ // 加载标签库驱动  
  155.         if(require_array(array(  
  156.             EXTEND_PATH.'Driver/TagLib/'.$file,  
  157.             CORE_PATH.'Driver/TagLib/'.$file),true)) {  
  158.             return ;  
  159.         }  
  160.     }  
  161.   
  162.     // 根据自动加载路径设置进行尝试搜索  
  163.     $paths  =   explode(',',C('APP_AUTOLOAD_PATH'));  
  164.     foreach ($paths as $path){  
  165.         if(import($path.'.'.$class))  
  166.             // 如果加载类成功则返回  
  167.             return ;  
  168.     }  
  169. }  

接着执行Session初始化操作,记录应用初始化时间


10)前面的准备工作都做完后,接下来便进入执行应用程序App::exec()方法了,到这一步时,基本就是水到渠成的了,利用前面获取的模块和方法通过检测方法是否存在,并通过ReflectionMethod类来获悉当前调试的类的信息,并且判断当前执行方法是否为public属性,不是的话抛出异常,是的话,便调用invoke方法执行类方法,接下里便是自己的代码了,同时注意的是在解析sql语句的时候执行的tp里的方法。


ok,流程跑了一遍,自己感觉清晰多了,以前就是在项目里写代码,从不看tp的源代码的,今天过了下,感觉良好,下次多过几遍,把里面的精髓掌握住,就写到这里。

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 硬盘显示不出来怎么办 硬盘插上不显示怎么办 mac不能读取移动硬盘怎么办 mac系统坏了怎么办 ip地址网站打不开怎么办? 电脑页面偏了怎么办 wifi被禁止联网怎么办 oppo浏览器屏蔽网站怎么办 被网站禁言怎么办 网站被模仿了怎么办 公积金不允许提取还房贷怎么办 电脑超出频率限制怎么办 海带宝转运丢失怎么办 xp电脑证书过期怎么办 电脑qq重复登录怎么办 海带宝少东西怎么办 苹果手机照片打不开怎么办 旧电脑没有密码了怎么办 快手忘记登录账号怎么办 b站永久封禁怎么办 微博自动关注怎么办 微博会自动点赞怎么办 游戏名字被占用怎么办 闲鱼头像违规怎么办 请求状态码错误怎么办 微博错误20521怎么办 忘记申请的邮箱怎么办 填写简历忘记邮箱怎么办 雅虎邮箱忘记用户名怎么办 oppo手机忘记密码怎么办 设备昵称忘了怎么办 快手昵称被注册怎么办 app占用越来越大怎么办 淘宝昵称被占用怎么办 电脑开机时间不准怎么办 电脑的时间不对怎么办 做完运动饿了怎么办 qq被冻结七天怎么办 12306电话号码忘了怎么办 新教练没会员怎么办 微博转发频繁怎么办