經過前面幾節的內容,咱們從零開始搭建了一個很是方便的MVC框架,理解了 CodeIgniter 框架最核心的部分。然而一個框架的便利不單單在於提供一個MVC就能夠了,它還必須具備較高的擴展性。下面將從 CodeIgniter 的官方文檔中的順序一步一步充實咱們這個「醜陋」 的框架。php
本課將實現 CodeIgniter 類庫加載的模式,對應於http://codeigniter.org.cn/user_guide/general/libraries.htmlhtml
首先類庫加載設計在 Loader 類中,函數命名爲 library,以下所示數組
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); }
與 model 相似,它首先判斷傳入的第一個參數是否爲數組,若是是的話,就遞歸調用一次。app
它經過調用 _ci_load_class 函數來實際加載具體的類。框架
protected function _ci_load_class($class, $params = NULL, $object_name = NULL) { $class = str_replace('.php', '', trim($class, '/')); $subdir = ''; if (($last_slash = strrpos($class, '/')) !== FALSE) { // 提取出路徑 $subdir = substr($class, 0, $last_slash + 1); // 提取出 class $class = substr($class, $last_slash + 1); } foreach (array(ucfirst($class), strtolower($class)) as $class) { $subclass = APPPATH.'libraries/'.$subdir.config_item('subclass_prefix').$class.'.php'; // class 擴展 if (file_exists($subclass)) { $baseclass = BASEPATH.'libraries/'.ucfirst($class).'.php'; if ( ! file_exists($baseclass)) { log_message('error', 'Unable to load the requested class: '.$class); show_error('Unable to load the requested class: '.$class); } // 檢查 class 是否加載過 if (in_array($subclass, $this->_ci_loaded_files)) { if (! is_null($object_name)) { $CI =& get_instance(); if ( ! isset($CI->$object_name)) { return $this->_ci_init_class($class, config_item('subclass_prefix'), $params, $object_name); } } $is_duplicate = TRUE; log_message('debug', $class." class already loaded. Second attempt ignored."); return; } include_once($baseclass); include_once($subclass); $this->_ci_loaded_files[] = $subclass; return $this->_ci_init_class($class, config_item('subclass_prefix'), $params, $object_name); } } if ($is_duplicate == FALSE) { log_message('error', 'Unable to load the requested class: '.$class); show_error("Unable to load the requested class: ".$class); } }
按照 CodeIgniter 的思路,首先會對加載函數的第一個參數路徑進行拆分,獲得具體的路徑和文件名,由於文件名會有一些特殊的約定。ide
CodeIgniter 在設計的時候有個很重要的思想,就是區分 system 和 application 兩種類型的代碼,從而設計出靈活性很高的框架,那麼針對 類庫 而言,就是在 system 中提供一些經常使用的類庫,而後給用戶在這個基礎上擴展或覆蓋的權利,另外,也能夠直接在 函數
application 文件夾下設計出徹底自定義的類。codeigniter
本節主要實現 在原有類上進行擴展 的代碼ui
1) 首先判斷 application 文件夾下是否存在按照約定命名的擴展類庫文件,即 subclass_prefix = 'MY_', 就判斷是否存在 MY_類庫名.php 文件this
2)若是存在,則加載基類庫文件,所有 include 以後,就能夠 _ci_init_class 了
public function _ci_init_class($class, $prefix = '', $config = FALSE, $object_name = NULL) { if ($prefix == '') { $name = $class; } else { $name = $prefix.$class; } if ( ! class_exists($name)) { log_message('error', "Non-existent class: ".$name); show_error("Non-existent class: ".$class); } $class = strtolower($class); $classvar = $class; $CI =& get_instance(); if ($config !== NULL) { $CI->$classvar = new $name($config); } else { $CI->$classvar = new $name; } }
而後經過
$CI->$classvar = new $name($config);
成爲 CI 核心對象的成員,從而就能夠很方便的訪問了~ $this->email->函數名();