程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> 關於PHP編程 >> ThinkPHP框架引導類分析

ThinkPHP框架引導類分析

編輯:關於PHP編程

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

該類可以說是ThinkPHP框架最為核心的類庫,負責諸多配置加載,注冊核心系統擴展(自動加載類庫、異常處理、錯誤處理等),管理和維護類實例、別名映射,可以一說是一個框架的工廠(該類有些許面向對象弊端,比如:違背了面向對象單一職責,其負責功能復雜,關聯類庫和文件較多,有動一牽百的憂慮)。類中遇到的函數會在該類分析之後徹底分析,所涉及的其它類庫會專門講解。

一、類結構

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='') {}//取得對象實例 支持調用類的靜態方法
    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框架的引導接口,實現錯誤、異常處理,配置加載,別名映射,行為注冊,包含運行緩存的生成,網站應用目錄檢測,自動類庫加載行為注冊。

/**
     * 應用程序初始化
     * @access public
     * @return void
     */
    static public function start() {
    	//使用spl標准庫中提供__autoload()函數的默認實現,比__autoload()效率更高,更加靈活
    	//一下可以使用spl_autoload_register(array('Think\Think','autoload'));
    	//建議使用spl_autoload_register(__NAMESPACE__.'\Think::autoload');實現
    	//一下所有注冊方式均可以使用上面3中形式傳遞參數
    	spl_autoload_register('Think\Think::autoload');
    	
    	//注冊全局腳本"析構函數",使用該方式注冊的函數,會在腳本結束前調用,大多數情況用來處理致命錯誤
    	register_shutdown_function('Think\Think::fatalError');
    	//設置自定義錯誤處理函數,用於處理錯誤信息
    	set_error_handler('Think\Think::appError');
    	//設置未異常處理函數
    	set_exception_handler('Think\Think::appException');
    	//可以把register_shutdown_function(),set_error_handler(),set_error_handler()3個函數組合完成自定義、多元化的錯誤處理模塊
    	
    	//根據STORAGE_TYPE的值設置分布式文件存儲方案,Storage是一個工廠類,用於管理和維護分布式文件存儲組件
    	//後面會詳細講解Storage類,並指出設計缺陷
    	Storage::connect(STORAGE_TYPE);
    	
    	//根據運行模式在運行緩存目錄下生成編譯緩存文件APP_MODE.'~runtime.php',從而減少IO開銷
    	//下面會詳細介紹生成緩存文件的方式
    	$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_PATH.APP_MODE.'.php',運行模式配置文件會影響下列加載不同的類庫和配置
    		//運行配置文件後期會詳細講解
    		$mode   =   include is_file(CONF_PATH.'core.php')?CONF_PATH.'core.php':MODE_PATH.APP_MODE.'.php';
    	
    		//以下所有配置項加載都會根據加載的先後順序覆蓋之前的配置項,一般都是先加載ThinkPHP默認配置,再加載應用配置
    		//core下標決定要加載的核心類和函數文件
    		foreach ($mode['core'] as $file){
    			if(is_file($file)) {
    				include $file;
    				//如果不是調試模式,則編譯該文件內容並儲存到預編譯內容變量中
    				if(!APP_DEBUG) $content   .= compile($file);
    			}
    		}
    
    		//config下標決定要加載的核心配置文件
    		foreach ($mode['config'] as $key=>$file){
    			//判斷下標是否為數字,如果不是就會把該配置文件中的配置項加載到對應的鍵下面,相當於給配置項增加一個緯度
    			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下標記錄類庫別名映射規則,ThinkPHP獨創別名機制,用於提升自動加載的效率
    		if(isset($mode['alias'])){
    			//由這句代碼可以看出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');
    
    		//tags下標用於標識系統行為,行為擴展具體由Hook鉤子類實現
    		if(isset($mode['tags'])) {
    			//由這句代碼可以看出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');
    
    		//加載框架底層語言包,有核心配置文件中的DEFAULT_LANG配置項決定
    		L(include THINK_PATH.'Lang/'.strtolower(C('DEFAULT_LANG')).'.php');
    
    		//如果不是調試模式則生成編譯緩存文件
    		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變量內容去除注釋和換行、空隔之後寫入到運行時編譯緩存文件
    			Storage::put($runtimefile,strip_whitespace('

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

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