- <?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(!emptyempty($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 (!emptyempty($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;
- }
- }
- }// 這個是 記錄 信息的整理了
- }
新聞熱點
疑難解答
圖片精選