thinkphp核心源码注释|Think.class.php

来源:互联网 发布:怎么用指针指向数组 编辑:程序博客网 时间:2024/04/29 10:35
<?php// +----------------------------------------------------------------------// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]// +----------------------------------------------------------------------// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.// +----------------------------------------------------------------------// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )// +----------------------------------------------------------------------// | Author: liu21st <liu21st@gmail.com>// +----------------------------------------------------------------------namespace Think;/** * ThinkPHP 引导类 * 开始了 最后的攻坚了 */class Think {    // 类映射    private static $_map      = array(); // 仓库 类型    // 实例化对象    private static $_instance = array(); // 实例化 的位置    /**     * 应用程序初始化     * @access public     * @return void     */    static public function start() { // 开始 初始了        // 第一步:先注册 各种方式。      // 注册AUTOLOAD方法      spl_autoload_register('Think\Think::autoload');    // 注册 自动执行函数      // 设定错误和异常处理        // 异常关闭      register_shutdown_function('Think\Think::fatalError'); //.也就是说当我们的脚本执行完成或意外死掉导致PHP执行即将关闭时,我们的这个函数将会 被调用.      // 错误        set_error_handler('Think\Think::appError'); // 设置 错误处理 方式      // 异常        set_exception_handler('Think\Think::appException');// 设置 异常处理 方式      // 初始化文件存储方式  第二步:文件存储      Storage::connect(STORAGE_TYPE); // 初始化文件 存储        // 第三步:缓存文件开始      $runtimefile  = RUNTIME_PATH.APP_MODE.'~runtime.php'; // 初始化 生成文件 开始      if(!APP_DEBUG && Storage::has($runtimefile)){ //非调试模式          Storage::load($runtimefile); // 加载文件      }else{          // 调试模式          if(Storage::has($runtimefile))              Storage::unlink($runtimefile);// 先删掉          $content =  '';// 内容 准备 出来了          // 读取应用模式          $mode   =   include is_file(CONF_PATH.'core.php')?CONF_PATH.'core.php':MODE_PATH.APP_MODE.'.php';// 读取 配置 文件          // 加载核心文件          foreach ($mode['core'] as $file){              if(is_file($file)) {                include $file;                if(!APP_DEBUG) $content   .= compile($file);              }          }// 文件加载          // 加载应用模式配置文件          foreach ($mode['config'] as $key=>$file){              is_numeric($key)?C(load_config($file)):C($key,load_config($file));          }          // 读取当前应用模式对应的配置文件          if('common' != APP_MODE && is_file(CONF_PATH.'config_'.APP_MODE.CONF_EXT))              C(load_config(CONF_PATH.'config_'.APP_MODE.CONF_EXT));            // 加载模式别名定义          if(isset($mode['alias'])){              self::addMap(is_array($mode['alias'])?$mode['alias']:include $mode['alias']);          }          // 加载应用别名定义文件          if(is_file(CONF_PATH.'alias.php'))              self::addMap(include CONF_PATH.'alias.php');          // 加载模式行为定义          if(isset($mode['tags'])) {              Hook::import(is_array($mode['tags'])?$mode['tags']:include $mode['tags']);          }          // 加载应用行为定义          if(is_file(CONF_PATH.'tags.php'))              // 允许应用增加开发模式配置定义              Hook::import(include CONF_PATH.'tags.php');             // 加载框架底层语言包          L(include THINK_PATH.'Lang/'.strtolower(C('DEFAULT_LANG')).'.php');          if(!APP_DEBUG){              $content  .=  "\nnamespace { Think\\Think::addMap(".var_export(self::$_map,true).");";              $content  .=  "\nL(".var_export(L(),true).");\nC(".var_export(C(),true).');Think\Hook::import('.var_export(Hook::get(),true).');}';              Storage::put($runtimefile,strip_whitespace('<?php '.$content));          }else{            // 调试模式加载系统默认的配置文件            C(include THINK_PATH.'Conf/debug.php');            // 读取应用调试配置文件            if(is_file(CONF_PATH.'debug'.CONF_EXT))                C(include CONF_PATH.'debug'.CONF_EXT);                     }      }// 加载各种 生成 文件      // 读取当前应用状态对应的配置文件      if(APP_STATUS && is_file(CONF_PATH.APP_STATUS.CONF_EXT))          C(include CONF_PATH.APP_STATUS.CONF_EXT);   // 读取当前的配置,临时配置文件      // 设置系统时区      date_default_timezone_set(C('DEFAULT_TIMEZONE'));      // 检查应用目录结构 如果不存在则自动创建      if(C('CHECK_APP_DIR')) {          $module     =   defined('BIND_MODULE') ? BIND_MODULE : C('DEFAULT_MODULE');          if(!is_dir(APP_PATH.$module) || !is_dir(LOG_PATH)){              // 检测应用目录结构              Build::checkDir($module);          }      }// 创建 需要创建的文件      // 记录加载文件时间      G('loadTime');      // 运行应用      App::run(); // 开始运行 其它的代码了。    }// 初始化 开始    // 注册classmap    static public function addMap($class, $map=''){        if(is_array($class)){            self::$_map = array_merge(self::$_map, $class);        }else{            self::$_map[$class] = $map;        }            } // 这个 确实 是注册 classmap 开始    // 获取classmap    static public function getMap($class=''){        if(''===$class){            return self::$_map;        }elseif(isset(self::$_map[$class])){            return self::$_map[$class];        }else{            return null;        }    }// 获取了 里面的  东西了。    /**     * 类库自动加载     * @param string $class 对象类名     * @return void     * 类库依赖加载     */    public static function autoload($class) {        // 检查是否存在映射        if(isset(self::$_map[$class])) {            include self::$_map[$class]; // 这里是这样的 包含对应的类文件的加载。        }elseif(false !== strpos($class,'\\')){ // 如果 不是 那种带有 命名空间的 里面            // echo strstr("Hello world!","world",true); 显示 hello          $name           =   strstr($class, '\\', true); //strstr(string,search,before_search)          if(in_array($name,array('Think','Org','Behavior','Com','Vendor')) || is_dir(LIB_PATH.$name)){               // Library目录下面的命名空间自动定位              $path       =   LIB_PATH; // 在这里的 开始 路径的准备了。          }else{              // 检测自定义命名空间 否则就以模块为命名空间              $namespace  =   C('AUTOLOAD_NAMESPACE'); // 模块的 命名空间了              $path       =   isset($namespace[$name])? dirname($namespace[$name]).'/' : APP_PATH;          }// 开始检测了          $filename       =   $path . str_replace('\\', '/', $class) . EXT;            // 终于找到了对应的 文件 位置          if(is_file($filename)) {              // Win环境下面严格区分大小写              if (IS_WIN && false === strpos(str_replace('/', '\\', realpath($filename)), $class . EXT)){                  return ;              }              include $filename; // 包含文件          }        }elseif (!C('APP_USE_NAMESPACE')) { // 'APP_USE_NAMESPACE'     =>  true,    // 应用类库是否使用命名空间            // 自动加载的类库层            foreach(explode(',',C('APP_AUTOLOAD_LAYER')) as $layer){                if(substr($class,-strlen($layer))==$layer){                    if(require_cache(MODULE_PATH.$layer.'/'.$class.EXT)) {                        return ;                    }                }                        }// 自动 加载文件 缓存文件            // 根据自动加载路径设置进行尝试搜索            foreach (explode(',',C('APP_AUTOLOAD_PATH')) as $path){                if(import($path.'.'.$class))                    // 如果加载类成功则返回                    return ;            }        }    }// 总结:就是 根据 文件名 之类的 解析了 对应的 类。    /**     * 取得对象实例 支持调用类的静态方法     * @param string $class 对象类名     * @param string $method 类的静态方法名     * @return object     */    static public function instance($class,$method='') { // 这种就是实例了        $identify   =   $class.$method;// 连接了        if(!isset(self::$_instance[$identify])) {            if(class_exists($class)){                $o = new $class();                if(!empty($method) && method_exists($o,$method))                    self::$_instance[$identify] = call_user_func(array(&$o, $method));                else                    self::$_instance[$identify] = $o;            }            else                self::halt(L('_CLASS_NOT_EXIST_').':'.$class);        }        return self::$_instance[$identify];    } // 总结:就是调用到实际里面的 method 里面的东西    /**     * 自定义异常处理     * @access public     * @param mixed $e 异常对象     */    static public function appException($e) {        $error = array();        $error['message']   =   $e->getMessage(); // 获取信息        $trace              =   $e->getTrace();// 获取错误信息        if('E'==$trace[0]['function']) {// 里面 开始            $error['file']  =   $trace[0]['file'];            $error['line']  =   $trace[0]['line'];        }else{// 对的            $error['file']  =   $e->getFile(); //获取文件            $error['line']  =   $e->getLine(); // 获取 line        }        $error['trace']     =   $e->getTraceAsString(); // 弄成字符串        Log::record($error['message'],Log::ERR);// 日志记录        // 发送404信息        header('HTTP/1.1 404 Not Found');        header('Status:404 Not Found');        self::halt($error);// 异常开始    }    /**     * 自定义错误处理     * @access public     * @param int $errno 错误类型     * @param string $errstr 错误信息     * @param string $errfile 错误文件     * @param int $errline 错误行数     * @return void     */    static public function appError($errno, $errstr, $errfile, $errline) {      switch ($errno) {          case E_ERROR:          case E_PARSE:          case E_CORE_ERROR:          case E_COMPILE_ERROR:          case E_USER_ERROR:            ob_end_clean();            $errorStr = "$errstr ".$errfile." 第 $errline 行.";            if(C('LOG_RECORD')) Log::write("[$errno] ".$errorStr,Log::ERR);            self::halt($errorStr);            break;          default:            $errorStr = "[$errno] $errstr ".$errfile." 第 $errline 行.";            self::trace($errorStr,'','NOTIC');            break;      }    }// 总结: 记录 外加 报错    // 致命错误捕获    static public function fatalError() {        Log::save();        if ($e = error_get_last()) {            switch($e['type']){              case E_ERROR:              case E_PARSE:              case E_CORE_ERROR:              case E_COMPILE_ERROR:              case E_USER_ERROR:                  ob_end_clean();                self::halt($e);                break;            }        }    }// 致命错误    /**     * 错误输出     * @param mixed $error 错误     * @return void     */    static public function halt($error) {        $e = array();// 内容开始        if (APP_DEBUG || IS_CLI) {            //调试模式下输出错误信息            if (!is_array($error)) { // 这里的还要分 字符串  或者是 数组                $trace          = debug_backtrace();                $e['message']   = $error;                $e['file']      = $trace[0]['file'];                $e['line']      = $trace[0]['line'];                ob_start();                debug_print_backtrace();                $e['trace']     = ob_get_clean();            } else {                $e              = $error;            }            if(IS_CLI){// 直接 就开始了                exit(iconv('UTF-8','gbk',$e['message']).PHP_EOL.'FILE: '.$e['file'].'('.$e['line'].')'.PHP_EOL.$e['trace']);            }        } else {            //否则定向到错误页面            $error_page         = C('ERROR_PAGE');            if (!empty($error_page)) {                redirect($error_page);// 直接 跳转            } else {                $message        = is_array($error) ? $error['message'] : $error;                $e['message']   = C('SHOW_ERROR_MSG')? $message : C('ERROR_MESSAGE');            }        }        // 包含异常页面模板        $exceptionFile =  C('TMPL_EXCEPTION_FILE',null,THINK_PATH.'Tpl/think_exception.tpl');        include $exceptionFile;// 包含模版 并且退出        exit;    } // 包含模版 并且退出    // 总结: 这里的 不能    /**     * 添加和获取页面Trace记录     * @param string $value 变量     * @param string $label 标签     * @param string $level 日志级别(或者页面Trace的选项卡)     * @param boolean $record 是否记录日志     * @return void|array     */    static public function trace($value='[think]',$label='',$level='DEBUG',$record=false) {        static $_trace =  array();// 这里的 又是静态仓库了,在一次运行中,要跑这么多东西,好累啊!        if('[think]' === $value){ // 获取trace信息            return $_trace;// 也就是 默认的 返回了        }else{            $info   =   ($label?$label.':':'').print_r($value,true); // 这种是输出 到字符串            $level  =   strtoupper($level);// 转换成为了            if((defined('IS_AJAX') && IS_AJAX) || !C('SHOW_PAGE_TRACE')  || $record) {                Log::record($info,$level,$record); // 记录日志            }else{                if(!isset($_trace[$level]) || count($_trace[$level])>C('TRACE_MAX_RECORD')) {                    $_trace[$level] =   array();                }                $_trace[$level][]   =   $info;            }        }    }// 这个是 记录 信息的整理了}

0 0