本篇并不是對某一組件的詳細(xì)源碼分析,而只是簡單的跟蹤了下CI的autoload的基本流程。因此,可以看做是Loader組件的分析前篇。
CI框架中,允許你配置autoload數(shù)組,這樣,在你的應(yīng)用程序初始化時,會自動加載相應(yīng)的類庫,例如,在application/config/autoload.php中,autoload的配置如下:
$autoload['libraries'] = array("smarty", "redis");
則CI框架初始化時,會自動加載libraries下面的smarty.php和redis.php,并且在你的應(yīng)用程序控制器中,可以通過$this->smarty->xxx 和$this->redis->yyy的方式調(diào)用你的類庫。
CI允許autoload中配置的自動加載的類別有:
1.Packages ---包2.Libraries --類庫3.Helper files ---用戶自定義的輔助文件4.Custom config files ---用戶自定義配置文件5.Language files ---語言包6.Models ---模型類
我們接下來以Libraries的自動加載為例,在追蹤CI的autoload之路。
由于Loader是CI中組件加載的管理器,而Loader是在CI_Controller中被加載的,因此我們從Controller加載Loader組件開始追蹤。
1. CI_Controller在CI_Controller中追蹤到這樣一句話:
$this->load =& load_class('Loader', 'core');$this->load->initialize();
于是我們猜想,在Loader的initialize的過程中,對autoload做了相應(yīng)的處理。
2. Loader的initialize方法實現(xiàn)public function initialize(){ $this->_ci_classes = array(); $this->_ci_loaded_files = array(); $this->_ci_models = array(); $this->_base_classes =& is_loaded(); $this->_ci_autoloader();//注意這里,看方法的名字,也可以猜到是對autoload的處理 return $this;}
Initialize的前面四個語句,用于對本身的屬性、參數(shù)等初始化,不是我們需要關(guān)心的內(nèi)容,真正執(zhí)行autoload的應(yīng)該是$this->_ci_autoloader(),沿著該線索,我們進(jìn)入_ci_autoload的內(nèi)部:
3. _ci_autoloader的方法:(1).首先引入autoload的配置數(shù)組:
if (defined('ENVIRONMENT') AND file_exists(APPPATH.'config/'.ENVIRONMENT.'/autoload.php')){ include(APPPATH.'config/'.ENVIRONMENT.'/autoload.php');}else{ include(APPPATH.'config/autoload.php');}
(2). 由于我們這次只追蹤libraries的autoload機制,因此我們略過對packages和config等的autoload處理機制,而直接尋找對libraries的處理:
if (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){ //ignore database eg. foreach ($autoload['libraries'] as $item) { $this->library($item); }}
可以看出,對所有的autoload的libraries,實際上是執(zhí)行了library方法,再次進(jìn)入library方法查看。
4. library方法實現(xiàn)。上述對該方法的調(diào)用中,傳遞的是autoload中配置的類庫名(我們的例子是redis和smarty),library方法的具體實現(xiàn):
public function library($library = '', $params = NULL, $object_name = NULL){if (is_array($library)){foreach ($library as $class){$this->library($class, $params);}return;}if ($library == '' OR isset($this->_base_classes[$library])){return FALSE;}if ( ! is_null($params) && ! is_array($params)){$params = NULL;}$this->_ci_load_class($library, $params, $object_name);}
可以看出,如果$library是數(shù)組,則會循環(huán)調(diào)用library方法。實際上最終會調(diào)用$this->_ci_load_class。再次進(jìn)入_ci_load_class查看.
5. _ci_load_class的實現(xiàn)撇開其中的錯誤檢查和安全檢查,我們只看關(guān)鍵的代碼:
return $this->_ci_init_class($class, config_item('subclass_該方法,將對類庫的初始化拋給了_ci_init_class處理:
$CI =& get_instance();//獲取Controller的實例if ($config !== NULL){ $CI->$classvar = new $name($config);}else{ $CI->$classvar = new $name;}到這里,我們總算了解了CI的autoload的基本流程(漫漫長征),作為對Loader組件的初步追蹤,我們省略了中的許多實現(xiàn)細(xì)節(jié),這些我們將在對Loader組件的分析過程中慢慢添加上。
總結(jié)一下autoload的基本流程:
1. Application/config/autoload.php中配置需要autoload的類庫2. Controller實例化的時候,會加載Loader組件,并調(diào)用該組件的initialize方法,對需要的資源初始化.3. 經(jīng)過更多的錯誤檢查和安全性檢查的步驟,加載需要的類庫、配置等。最后說一句,并不是所有的類庫都需要通過CI的autoload加載,因為該類庫在框架初始化的時候就被加載,而不管你是不是需要使用該類庫,這樣實際上會有一定的性能損失。如果你的類庫并不是所有應(yīng)用都需要的,那么,更好的方法是需要時再加載。關(guān)于這一點,我們之后在分析Loader組件的設(shè)計和實現(xiàn)時會進(jìn)一步詳細(xì)說明。
本篇的參考文獻(xiàn):1. http://itopic.org/codeigniter-config-autoload.html
2. http://codeigniter.org.cn/user_guide/general/autoloader.html
新聞熱點
疑難解答