亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

首頁 php教程 php手冊 ThinkPHP框架引導類的示例代碼分析

ThinkPHP框架引導類的示例代碼分析

Apr 21, 2017 am 09:37 AM

該類文件在:ThinkPHP/Library/Think/Think.class.php

?????? 該類可以說是ThinkPHP框架最為核心的類庫,負責諸多配置加載,注冊核心系統(tǒng)擴展(自動加載類庫、異常處理、錯誤處理等),管理和維護類實例、別名映射,可以一說是一個框架的工廠(該類有些許面向?qū)ο蟊锥?,比如:違背了面向?qū)ο髥我宦氊?,其負責功能復雜,關聯(lián)類庫和文件較多,有動一牽百的憂慮)。類中遇到的函數(shù)會在該類分析之后徹底分析,所涉及的其它類庫會專門講解。

一、類結(jié)構?

namespace Think;//定義命名空間
class Think {
    private static $_map      = array();//類庫別名映射
    private static $_instance = array();//保存類實例(這么說也不合理,等會分析該功能時具體說明)
    static public function start() {}//應用程序初始化
    static public function addMap($class, $map=''){}// 注冊classmap
    static public function getMap($class=''){}// 獲取classmap
    public static function autoload($class) {}//類庫自動加載
    static public function instance($class,$method='') {}//取得對象實例 支持調(diào)用類的靜態(tài)方法
    static public function appException($e) {}//自定義異常處理
    static public function appError($errno, $errstr, $errfile, $errline) {}//自定義錯誤處理
    static public function fatalError() {} // 致命錯誤捕獲
    static public function halt($error) {}//錯誤輸出
    static public function trace($value='[think]',$label='',$level='DEBUG',$record=false) {}//添加和獲取頁面Trace記錄
}

二、應用程序初始化start()方法分析,該方法包含一套錯誤和異常處理機制,非常受用。該方法作為ThinkPHP框架的引導接口,實現(xiàn)錯誤、異常處理,配置加載,別名映射,行為注冊,包含運行緩存的生成,網(wǎng)站應用目錄檢測,自動類庫加載行為注冊。

/**
     * 應用程序初始化
     * @access public
     * @return void
     */
    static public function start() {
    	//使用spl標準庫中提供__autoload()函數(shù)的默認實現(xiàn),比__autoload()效率更高,更加靈活
    	//一下可以使用spl_autoload_register(array('Think\Think','autoload'));
    	//建議使用spl_autoload_register(__NAMESPACE__.'\Think::autoload');實現(xiàn)
    	//一下所有注冊方式均可以使用上面3中形式傳遞參數(shù)
    	spl_autoload_register('Think\Think::autoload');
    	
    	//注冊全局腳本"析構函數(shù)",使用該方式注冊的函數(shù),會在腳本結(jié)束前調(diào)用,大多數(shù)情況用來處理致命錯誤
    	register_shutdown_function('Think\Think::fatalError');
    	//設置自定義錯誤處理函數(shù),用于處理錯誤信息
    	set_error_handler('Think\Think::appError');
    	//設置未異常處理函數(shù)
    	set_exception_handler('Think\Think::appException');
    	//可以把register_shutdown_function(),set_error_handler(),set_error_handler()3個函數(shù)組合完成自定義、多元化的錯誤處理模塊
    	
    	//根據(jù)STORAGE_TYPE的值設置分布式文件存儲方案,Storage是一個工廠類,用于管理和維護分布式文件存儲組件
    	//后面會詳細講解Storage類,并指出設計缺陷
    	Storage::connect(STORAGE_TYPE);
    	
    	//根據(jù)運行模式在運行緩存目錄下生成編譯緩存文件APP_MODE.'~runtime.php',從而減少IO開銷
    	//下面會詳細介紹生成緩存文件的方式
    	$runtimefile  = RUNTIME_PATH.APP_MODE.'~runtime.php';
    	
    	//如果不是在調(diào)試模式,并且編譯緩存文件存在,直接加載編譯緩存
    	if(!APP_DEBUG && Storage::has($runtimefile)){
    		Storage::load($runtimefile);
    	}else{
    		//判斷編譯緩存文件是否存在,存在就刪除
    		if(Storage::has($runtimefile))
    			Storage::unlink($runtimefile);
    		
    		//預編譯內(nèi)容變量
    		$content =  '';
    		//判斷是否存在運行模式配置文件,如果不存在就加載MODE_PATH.APP_MODE.'.php',運行模式配置文件會影響下列加載不同的類庫和配置
    		//運行配置文件后期會詳細講解
    		$mode   =   include is_file(CONF_PATH.'core.php')?CONF_PATH.'core.php':MODE_PATH.APP_MODE.'.php';
    	
    		//以下所有配置項加載都會根據(jù)加載的先后順序覆蓋之前的配置項,一般都是先加載ThinkPHP默認配置,再加載應用配置
    		//core下標決定要加載的核心類和函數(shù)文件
    		foreach ($mode['core'] as $file){
    			if(is_file($file)) {
    				include $file;
    				//如果不是調(diào)試模式,則編譯該文件內(nèi)容并儲存到預編譯內(nèi)容變量中
    				if(!APP_DEBUG) $content   .= compile($file);
    			}
    		}
    
    		//config下標決定要加載的核心配置文件
    		foreach ($mode['config'] as $key=>$file){
    			//判斷下標是否為數(shù)字,如果不是就會把該配置文件中的配置項加載到對應的鍵下面,相當于給配置項增加一個緯度
    			is_numeric($key)?C(include $file):C($key,include $file);
    		}
    
    		//如果不是普通運行模式,則判斷是否存在運行模式應用配置文件
    		if('common' != APP_MODE && is_file(CONF_PATH.'config_'.APP_MODE.'.php'))
    			C(include CONF_PATH.'config_'.APP_MODE.'.php');
    
    		//alias下標記錄類庫別名映射規(guī)則,ThinkPHP獨創(chuàng)別名機制,用于提升自動加載的效率
    		if(isset($mode['alias'])){
    			//由這句代碼可以看出alias規(guī)則可以是一個數(shù)組,或者將規(guī)則數(shù)組單獨作為一個文件
    			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');
    
    		//tags下標用于標識系統(tǒng)行為,行為擴展具體由Hook鉤子類實現(xiàn)
    		if(isset($mode['tags'])) {
    			//由這句代碼可以看出tags規(guī)則可以是一個數(shù)組,或者將規(guī)則數(shù)組單獨作為一個文件
    			Hook::import(is_array($mode['tags'])?$mode['tags']:include $mode['tags']);
    		}
    
    		//加載應用中的行為擴展配置
    		if(is_file(CONF_PATH.'tags.php'))
    			// 允許應用增加開發(fā)模式配置定義
    			Hook::import(include CONF_PATH.'tags.php');
    
    		//加載框架底層語言包,有核心配置文件中的DEFAULT_LANG配置項決定
    		L(include THINK_PATH.'Lang/'.strtolower(C('DEFAULT_LANG')).'.php');
    
    		//如果不是調(diào)試模式則生成編譯緩存文件
    		if(!APP_DEBUG){
    			//namespace {}這種方式用于聲明代碼塊中的命名空間屬于全局命名空間
    			//這句代碼用于生成加載別名映射的php代碼
    			$content  .=  "\nnamespace { Think\Think::addMap(".var_export(self::$_map,true).");";
    			//L(".var_export(L(),true).");生成語言加載代碼
    			//C(".var_export(C(),true).');生成配置項加載代碼
    			//Think\Hook::import('.var_export(Hook::get(),true).');生成鉤子加載代碼
    			$content  .=  "\nL(".var_export(L(),true).");\nC(".var_export(C(),true).');Think\Hook::import('.var_export(Hook::get(),true).');}';
    			//將$content變量內(nèi)容去除注釋和換行、空隔之后寫入到運行時編譯緩存文件
    			Storage::put($runtimefile,strip_whitespace(&#39;<?php &#39;.$content));
    		}else{
    			// 調(diào)試模式加載系統(tǒng)默認的配置文件
    			C(include THINK_PATH.&#39;Conf/debug.php&#39;);
    			// 讀取應用調(diào)試配置文件
    			if(is_file(CONF_PATH.&#39;debug.php&#39;))
    				C(include CONF_PATH.&#39;debug.php&#39;);
    		}
    	}
    
    	//根據(jù)APP_STATUS讀取當前部署環(huán)境配置文件,常用在上線前數(shù)據(jù)庫連接配置等,用于覆蓋默認配置行為
    	if(APP_STATUS && is_file(CONF_PATH.APP_STATUS.&#39;.php&#39;))
    		C(include CONF_PATH.APP_STATUS.&#39;.php&#39;);
    
    	// 設置系統(tǒng)時區(qū)
    	//建議可以寫成date_default_timezone_set(C(&#39;DEFAULT_TIMEZONE&#39;,null,&#39;PRC&#39;));防止配置項讀取問題導致的時區(qū)設置錯誤
    	date_default_timezone_set(C(&#39;DEFAULT_TIMEZONE&#39;));
    
    	// 檢查應用目錄結(jié)構 如果不存在則自動創(chuàng)建
    	if(C(&#39;CHECK_APP_DIR&#39;) && !is_dir(LOG_PATH)) {
    		//build.php負責創(chuàng)建應用目錄結(jié)構
    		require THINK_PATH.&#39;Common/build.php&#39;;
    	}
    
    	// 記錄加載文件時間
    	G(&#39;loadTime&#39;);
    	// 運行應用
    	App::run();
    }

三、類庫別名映射機制實現(xiàn)addMap()和getMap()方法分析;該機制使用Think::_map變量存儲別名映射記錄,通過Think::addMap()添加或修改別名映射記錄,使用Think:getMap()獲取別名映射記錄。

/**
     * 注冊或修改類庫別名映射記錄
     * @access public
     * @param class String|Array 如果為數(shù)組鍵為類庫別名,鍵值為類庫實際位置;如果字符串代表類庫別名
     * @param map   String 		    如果class為字符串,該參數(shù)代表類庫實際位置,否則沒有意義
     * @return void
     */
    static public function addMap($class, $map=&#39;&#39;){
    	//判斷class是否為數(shù)組,如果是就合并當前類庫別名記錄,如果有相同記錄就會覆蓋
    	if(is_array($class)){
    		self::$_map = array_merge(self::$_map, $class);
    	}else{
    		//如果class不是數(shù)組,就作為別名儲存在類庫別名記錄中,并把map作為實際類庫位置
    		self::$_map[$class] = $map;
    	}
    }
    
    /**
     * 根據(jù)別名獲取類庫實際地址
     * @param class String 	類庫別名
     * @return Array|String|NULL	如果class為空則獲取所有類庫別名記錄,否者返回別名對應的類庫位置
     */
    static public function getMap($class=&#39;&#39;){
    	//如果class為空,直接返回所有類庫別名記錄
    	if(&#39;&#39;===$class){
    		return self::$_map;
    		//判斷對應別名是否在別名映射記錄中,如果存在返回類庫實際地址,否者返回null
    	}elseif(isset(self::$_map[$class])){
    		return self::$_map[$class];
    	}else{
    		return null;
    	}
    }

四、ThinkPHP類庫自動加載機制autoload()方法分析,該方法是由Think::start()方法中的第一句代碼注冊實現(xiàn)spl_autoload_register('Think\Think::autoload');

/**
     * 類庫自動加載
     * @param string $class 對象類名
     * @return void
     */
    public static function autoload($class) {
        //判斷是否存在別名映射
        //標記一處bug,如果使用Think::addMap(&#39;Think\Test&#39;);注冊別名就完了,程序邏輯不嚴謹,不會有大的安全問題,可以無視
        //具體可以看Think::addMap()方法的實現(xiàn)        
        if(isset(self::$_map[$class])) {
            include self::$_map[$class];
            //建議在這里renturn;
            
        //判斷是否存在\符號,存在則使用命名空間加載機制
        //此處與配置說明不符&#39;APP_AUTOLOAD_PATH&#39;     =>  &#39;&#39;, // 自動加載的路徑 關閉APP_USE_NAMESPACE后有效
        //現(xiàn)在判斷的是否在類名中使用命名規(guī)則而不是使用APP_USE_NAMESPACE配置,當然該項配置主要作用在路由模塊,后續(xù)會講解
        }elseif(strpos($class,&#39;\\&#39;)){
         //獲取命名空間的第一個命名范圍
          $name           =   strstr($class, &#39;\\&#39;, true);
          //判斷該命名空間的第一個命名范圍是否在Think約定范圍類,并在Library目錄下存在該目錄
          if(in_array($name,array(&#39;Think&#39;,&#39;Org&#39;,&#39;Behavior&#39;,&#39;Com&#39;,&#39;Vendor&#39;)) || is_dir(LIB_PATH.$name)){ 
              // Library目錄下面的命名空間自動定位
              $path       =   LIB_PATH;
          }else{
              //檢測自定義命名空間 否則就以模塊為命名空間
              $namespace  =   C(&#39;AUTOLOAD_NAMESPACE&#39;);
              $path       =   isset($namespace[$name])? dirname($namespace[$name]).&#39;/&#39; : APP_PATH;
          }
          //這里可以看出ThinkPHP命名空間的命名規(guī)則是以LIB_PATH和APP_PATH作為根目錄的目錄原則,也可以為AUTOLOAD_NAMESPACE配置項來自定義命名規(guī)則根目錄
          $filename       =   $path . str_replace(&#39;\\&#39;, &#39;/&#39;, $class) . EXT;
          
          //判斷文件是否存在,為啥在注冊別名的時候不去判斷文件是否存在呢?那樣是否可以無視一些有問題的別名映射,而使用正確的加載規(guī)則呢?
          if(is_file($filename)) {
              //如果在windows環(huán)境下運行,使用strpos來檢測是否大小寫一致問題,如果不一致直接返回
              if (IS_WIN && false === strpos(str_replace(&#39;/&#39;, &#39;\\&#39;, realpath($filename)), $class . EXT)){
                  return ;
              }
              
              //導入類文件
              include $filename;
              
              //這里建議return;
          }
        }else{
            //不用按照配置文件中的APP_USE_NAMESPACE的值來決定是否APP_AUTOLOAD_LAYER配置該項
            //只要在類庫加載中沒有使用命名空間就會調(diào)用以下規(guī)則來查找類庫(要實例化的類不能聲明命名規(guī)則)
            foreach(explode(&#39;,&#39;,C(&#39;APP_AUTOLOAD_LAYER&#39;)) as $layer){
            	//判斷類名最后幾位是否符合APP_AUTOLOAD_LAYER配置項
                if(substr($class,-strlen($layer))==$layer){
                	//加載當前模塊下對應的類文件,這個其實可以直接判斷文件是否存在,并用include加載即可,沒有必要調(diào)用require_cache函數(shù)
                	//以上是個人見解,緣由是因為上面的加載機制都沒有使用,我覺得是否應該統(tǒng)一,而且自動加載類文件,不用限制加載一次,如果已經(jīng)加載了,也不會調(diào)用這個方法了。
                    if(require_cache(MODULE_PATH.$layer.&#39;/&#39;.$class.EXT)) {
                    	//加載文件成功直接返回
                        return ;
                    }
                }            
            }
            
            //根據(jù)APP_AUTOLOAD_PATH配置設置的路徑規(guī)則自動搜索并加載文件
            foreach (explode(&#39;,&#39;,C(&#39;APP_AUTOLOAD_PATH&#39;)) as $path){
            	//這里同上,是否也可以不用調(diào)用import()方法加載,或者統(tǒng)一了呢?
                if(import($path.&#39;.&#39;.$class))
                    // 如果加載類成功則返回
                    return ;
            }
          }
    }

五、管理類實例或者'緩存'類靜態(tài)方法調(diào)用結(jié)果instance()方法分析,之前在類結(jié)構分析中說$_instance變量保存類實例并不合理,因為該類還可以調(diào)用類的靜態(tài)方法,并'緩存'結(jié)果。我在該方法注釋中提出一些個人見解,并不是說該方法設計的不合理,這個是畢竟是ThinkPHP專有方法,任何一個項目的設計都不會像我那般去考慮一個方法的諸多問題,首要問題是解決是否符合項目應用足矣。同樣看到這篇文章的朋友可以思考,在項目是否有很多類并不需要多個實例(沒有強制約束的情況下),如果有那可以設計一個適合自己項目的偽單例工廠來管理這些類的實例。

/**
     * 取得對象實例 支持調(diào)用類的靜態(tài)方法
     * 解析:我把該類看成一個偽單例工廠,不是嚴格要求類不許是單例,統(tǒng)一使用該方法獲取類對象,可以實現(xiàn)單例模式(極其適合php這種較為靈活的語言)
     * 		說這是一個單例模式工廠不合格,因為沒有嚴格要求所管理類必須符合單例模式約束。
     * 問題:該方法說此類可以調(diào)用類的靜態(tài)方法,并沒有約定靜態(tài)方法必須返回類的實例(self),可以返回任意結(jié)果,這個讓我很詫異
     * 		如果是想要緩存類方法調(diào)用結(jié)果,是否應該提供給方法傳遞參數(shù)選項呢?
     * 		如果僅僅為了管控類的實例(比如嚴格按照單例模式設計的類,如果要管理,必須使用靜態(tài)方法),是否應該說明或者在方法中檢測返回值呢?
     * 解惑:這個畢竟不是提供給應用的方法(當然可以使用,設計初衷肯定不是,這算是ThinkPHP開發(fā)團隊約定俗成的規(guī)定(口頭約束使用方法)吧?)
     * 		這至少給我們一個啟示,可以這么管理偽單例模式(口頭約束的方式,當然比之更可靠),之前我在一個項目中設計過這樣一個工廠類(那時候還沒有分析過任何產(chǎn)品的源碼)
     * @param string $class 對象類名
     * @param string $method 類的靜態(tài)方法名
     * @return object
     */
    static public function instance($class,$method=&#39;&#39;) {
    	//生成實例管理標識
        $identify   =   $class.$method;
        //判斷是否已經(jīng)存在改類實例標識
        if(!isset(self::$_instance[$identify])) {
        	//判斷類是否存在,這里反應不能使用自動加載機制,必須在調(diào)用該方法前加載類文件
            if(class_exists($class)){
            	//實例化類,這里可以看出并不能管理嚴格意義上的單例類
                $o = new $class();
                
                //判斷是否要調(diào)用靜態(tài)方法,并確定該類是否存在該方法
                if(!empty($method) && method_exists($o,$method))
                	//返回調(diào)用結(jié)果(不明確是什么)
                    self::$_instance[$identify] = call_user_func(array(&$o, $method));
                else
                	//存儲類實例對象
                    self::$_instance[$identify] = $o;
            }
            else
            	//輸出錯誤信息
                self::halt(L(&#39;_CLASS_NOT_EXIST_&#39;).&#39;:&#39;.$class);
        }
        //返回實例對象
        return self::$_instance[$identify];
    }

六、ThinkPHP內(nèi)置錯誤處理和異常處理實現(xiàn)分析。appException()方法由Think::start()中set_exception_handler('Think\Think::appException');語句實現(xiàn)。appError()方法由Think::start()中set_error_handler('Think\Think::appError');語句實現(xiàn),fatalError()方法由Think::start()中register_shutdown_function('Think\Think::fatalError');語句實現(xiàn)。halt()方法用來輸出重要錯誤信息和異常,并終止程序執(zhí)行。trace()方法用來記錄并管理Trace調(diào)試工具中的錯誤信息。

/**
     * 自定義異常處理
     * @access public
     * @param mixed $e 異常對象
     * @param void
     */
    static public function appException($e) {
        $error = array();
        //獲取異常錯誤信息
        $error[&#39;message&#39;]   =   $e->getMessage();
        //獲取backtrace()回溯信息
        $trace              =   $e->getTrace();
        //判斷是否由異常處理方法拋出,ThinkPHP自定義拋出異常處理函數(shù)
        if(&#39;E&#39;==$trace[0][&#39;function&#39;]) {
            $error[&#39;file&#39;]  =   $trace[0][&#39;file&#39;];//獲取錯誤文件
            $error[&#39;line&#39;]  =   $trace[0][&#39;line&#39;];//獲取錯誤行號
        }else{
            $error[&#39;file&#39;]  =   $e->getFile();//獲取錯誤文件
            $error[&#39;line&#39;]  =   $e->getLine();//獲取錯誤行號
        }
        //已格式錯誤回溯信息
        $error[&#39;trace&#39;]     =   $e->getTraceAsString();
        //寫入到錯誤日志
        Log::record($error[&#39;message&#39;],Log::ERR);
        // 發(fā)送404信息
        header(&#39;HTTP/1.1 404 Not Found&#39;);
        header(&#39;Status:404 Not Found&#39;);
        //顯示錯誤信息
        self::halt($error);
    }

    /**
     * 自定義錯誤處理
     * @access public
     * @param int $errno 錯誤類型
     * @param string $errstr 錯誤信息
     * @param string $errfile 錯誤文件
     * @param int $errline 錯誤行數(shù)
     * @return void
     */
    static public function appError($errno, $errstr, $errfile, $errline) {
      switch ($errno) {
      	  //一些重要的錯誤信息,會影響之后的程序執(zhí)行
          case E_ERROR:
          case E_PARSE:
          case E_CORE_ERROR:
          case E_COMPILE_ERROR:
          case E_USER_ERROR:
          	//清空輸出緩沖(不知道在哪里開啟了,后面分析會遇到)
            ob_end_clean();//其實就是把php默認輸出的錯誤信息清除掉
            //錯誤信息
            $errorStr = "$errstr ".$errfile." 第 $errline 行.";
            //根據(jù)LOG_RECORD是否記錄錯誤信息,決定是否寫入錯誤日志
            if(C(&#39;LOG_RECORD&#39;)) Log::write("[$errno] ".$errorStr,Log::ERR);
            //輸出錯誤信息
            self::halt($errorStr);
            break;
            
          //可以忽略的錯誤信息,不會輸出,會記錄到trace當中,使用SHOW_PAGE_TRACE配置可以查看的錯誤信息
          default:
          	//這里程序還要繼續(xù)執(zhí)行,不能清空輸出緩沖,如果不希望顯示這類錯誤信息,應當在php.ini中調(diào)節(jié),或者使用ini_set()的函數(shù)改變
            //錯誤信息
          	$errorStr = "[$errno] $errstr ".$errfile." 第 $errline 行.";
          	//記錄到trace當中
            self::trace($errorStr,&#39;&#39;,&#39;NOTIC&#39;);
            break;
      }
    }
    
    // 致命錯誤捕獲
    static public function fatalError() {
    	//致命錯誤必須保存到日志中
        Log::save();
        //獲取上一個錯誤信息,沒有錯誤就跳過了(⊙0⊙)
        if ($e = error_get_last()) {
        	//處理致命錯誤信息
            switch($e[&#39;type&#39;]){
              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();
        //判斷是否是調(diào)試模式,或者命令行模式
        if (APP_DEBUG || IS_CLI) {
            //調(diào)試模式下輸出錯誤信息
            //如果錯誤信息不是一個數(shù)組,就回溯最后一次執(zhí)行方法的信息
            if (!is_array($error)) {
                $trace          = debug_backtrace();
                $e[&#39;message&#39;]   = $error;
                $e[&#39;file&#39;]      = $trace[0][&#39;file&#39;];
                $e[&#39;line&#39;]      = $trace[0][&#39;line&#39;];
                ob_start();//開始輸出緩存
                debug_print_backtrace();//輸出一條回溯信息
                $e[&#39;trace&#39;]     = ob_get_clean();//獲取輸出緩沖信息,并清空
            } else {
                $e              = $error;
            }
            if(IS_CLI){
            	//命令行模式,轉(zhuǎn)換為gbk編碼,終止程序執(zhí)行并輸出錯誤信息
                exit(iconv(&#39;UTF-8&#39;,&#39;gbk&#39;,$e[&#39;message&#39;]).PHP_EOL.&#39;FILE: &#39;.$e[&#39;file&#39;].&#39;(&#39;.$e[&#39;line&#39;].&#39;)&#39;.PHP_EOL.$e[&#39;trace&#39;]);
            }
        } else {
            //不是調(diào)試模式,重定向到錯誤頁面
            $error_page         = C(&#39;ERROR_PAGE&#39;);//獲取設置的錯誤頁面
            if (!empty($error_page)) {
            	//重定向到錯誤頁面
                redirect($error_page);
            } else {
            	//根據(jù)SHOW_ERROR_MSG配置決定是否顯示詳細的錯誤信息,還是采用ERROR_MESSAGE設定的錯誤信息
                $message        = is_array($error) ? $error[&#39;message&#39;] : $error;
                $e[&#39;message&#39;]   = C(&#39;SHOW_ERROR_MSG&#39;)? $message : C(&#39;ERROR_MESSAGE&#39;);
            }
        }
        //根據(jù)TMPL_EXCEPTION_FILE配置決定調(diào)用錯誤信息顯示模版,否者采用ThinkPHP默認模版
        $exceptionFile =  C(&#39;TMPL_EXCEPTION_FILE&#39;,null,THINK_PATH.&#39;Tpl/think_exception.tpl&#39;);
        include $exceptionFile;
        exit;//終止程序運行,很重要的。
    }

    /**
     * 添加和獲取頁面Trace記錄
     * @param string $value 變量
     * @param string $label 標簽
     * @param string $level 日志級別(或者頁面Trace的選項卡)
     * @param boolean $record 是否記錄日志
     * @return void
     */
    static public function trace($value=&#39;[think]&#39;,$label=&#39;&#39;,$level=&#39;DEBUG&#39;,$record=false) {
    	//采用靜態(tài)變量存儲Trace記錄
        static $_trace =  array();
        if(&#39;[think]&#39; === $value){ // 獲取trace信息
            return $_trace;
        }else{
        	//錯誤信息
            $info   =   ($label?$label.&#39;:&#39;:&#39;&#39;).print_r($value,true);
            $level  =   strtoupper($level);//將錯誤級別轉(zhuǎn)換為大寫
            
            //如果是AjAX請求或者不顯示TRACE調(diào)試工具,或者$record要求記錄日志,就不會記錄該條錯誤信息
            if((defined(&#39;IS_AJAX&#39;) && IS_AJAX) || !C(&#39;SHOW_PAGE_TRACE&#39;)  || $record) {
                Log::record($info,$level,$record);//將錯誤信息寫入到日志文件
            }else{
            	//判斷錯誤等級是否存在或者該類錯誤信息是否達到錯誤類型記錄上限,由TRACE_MAX_RECORD配置
                if(!isset($_trace[$level]) || count($_trace[$level])>C(&#39;TRACE_MAX_RECORD&#39;)) {
                	//這里有個我很詫異的地方,當錯誤類別記錄達到錯誤類型記錄上限的是否為什么要重置該類型錯誤記錄
                	//而不是不記錄當前錯誤信息,或者刪除最先一條的錯誤信息,追加到最后
                	//我建議是不理會比較合理,因為調(diào)試錯誤,也有先后嗎,先把之前遇到的錯誤解決,就會看到新的錯誤了(這是否有點坑⊙0⊙)
                    $_trace[$level] =   array();
                }
                //按錯類別記錄錯誤信息
                $_trace[$level][]   =   $info;
            }
        }
    }

七、總結(jié):對該類分析,主要掌控php錯誤處理和異常處理方面的知識,并了解基于命名空間自動加載的規(guī)則定義基礎,同樣接觸了ThinkPHP運行時編譯緩存機制帶來的IO優(yōu)化思路以及類庫別名機制對與類自動加載帶來的優(yōu)化。在分析該類時站在ThinkPHP應用外對該類提出幾處質(zhì)疑,僅為個人對面向?qū)ο笤O計的理解和認知,不作為詳細參考。

本網(wǎng)站聲明
本文內(nèi)容由網(wǎng)友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發(fā)現(xiàn)涉嫌抄襲或侵權的內(nèi)容,請聯(lián)絡admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅(qū)動的應用程序,用於創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺化網(wǎng)頁開發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Laravel 教程
1597
29
PHP教程
1488
72
thinkphp專案怎麼運行 thinkphp專案怎麼運行 Apr 09, 2024 pm 05:33 PM

執(zhí)行 ThinkPHP 專案需要:安裝 Composer;使用 Composer 建立專案;進入專案目錄,執(zhí)行 php bin/console serve;造訪 http://localhost:8000 查看歡迎頁面。

thinkphp有幾個版本 thinkphp有幾個版本 Apr 09, 2024 pm 06:09 PM

ThinkPHP 擁有多個版本,針對不同 PHP 版本而設計。主要版本包括 3.2、5.0、5.1 和 6.0,而次要版本用於修復 bug 和提供新功能。目前最新穩(wěn)定版本為 ThinkPHP 6.0.16。在選擇版本時,需考慮 PHP 版本、功能需求和社群支援。建議使用最新穩(wěn)定版本以獲得最佳性能和支援。

thinkphp怎麼運行 thinkphp怎麼運行 Apr 09, 2024 pm 05:39 PM

ThinkPHP Framework 的本機運作步驟:下載並解壓縮 ThinkPHP Framework 到本機目錄。建立虛擬主機(可選),指向 ThinkPHP 根目錄。配置資料庫連線參數(shù)。啟動 Web 伺服器。初始化 ThinkPHP 應用程式。存取 ThinkPHP 應用程式 URL 運行。

laravel和thinkphp哪個好 laravel和thinkphp哪個好 Apr 09, 2024 pm 03:18 PM

Laravel 和 ThinkPHP 框架的效能比較:ThinkPHP 效能通常優(yōu)於 Laravel,專注於最佳化和快取。 Laravel 性能良好,但對於複雜應用程序,ThinkPHP 可能更適合。

thinkphp怎麼安裝 thinkphp怎麼安裝 Apr 09, 2024 pm 05:42 PM

ThinkPHP 安裝步驟:準備 PHP、Composer、MySQL 環(huán)境。使用 Composer 建立專案。安裝 ThinkPHP 框架及相依性。配置資料庫連線。產(chǎn)生應用程式碼。啟動應用程式並造訪 http://localhost:8000。

thinkphp效能怎麼樣 thinkphp效能怎麼樣 Apr 09, 2024 pm 05:24 PM

ThinkPHP 是一款高效能的 PHP 框架,具備快取機制、程式碼最佳化、平行處理和資料庫最佳化等優(yōu)勢。官方性能測試顯示,它每秒可處理超過 10,000 個請求,實際應用中被廣泛用於京東商城、攜程網(wǎng)等大型網(wǎng)站和企業(yè)系統(tǒng)。

開發(fā)建議:如何利用ThinkPHP框架進行API開發(fā) 開發(fā)建議:如何利用ThinkPHP框架進行API開發(fā) Nov 22, 2023 pm 05:18 PM

開發(fā)建議:如何利用ThinkPHP框架進行API開發(fā)隨著網(wǎng)際網(wǎng)路的不斷發(fā)展,API(ApplicationProgrammingInterface)的重要性也日益凸顯。 API是不同應用程式之間進行通訊的橋樑,它可以實現(xiàn)資料共享、功能呼叫等操作,為開發(fā)者提供了相對簡單且快速的開發(fā)方式。而ThinkPHP框架作為一款優(yōu)秀的PHP開發(fā)框架,具有高效能、可擴展且易用

開發(fā)建議:如何利用ThinkPHP框架實現(xiàn)非同步任務 開發(fā)建議:如何利用ThinkPHP框架實現(xiàn)非同步任務 Nov 22, 2023 pm 12:01 PM

《開發(fā)建議:如何利用ThinkPHP框架實現(xiàn)非同步任務》隨著網(wǎng)路技術的快速發(fā)展,Web應用程式對於處理大量並發(fā)請求和複雜業(yè)務邏輯的需求也越來越高。為了提高系統(tǒng)的效能和使用者體驗,開發(fā)人員常常會考慮利用非同步任務來執(zhí)行一些耗時操作,例如發(fā)送郵件、處理文件上傳、產(chǎn)生報表等。在PHP領域,ThinkPHP框架作為一個流行的開發(fā)框架,提供了一些便捷的方式來實現(xiàn)非同步任務。

See all articles