上一節簡單實現了 CI 的類庫擴展模型,因此 _ci_load_class 和 _ci_init_class 寫的不是很完備。根據上節課的分析,當 system/libraries 目錄下存在 Email.php, 而後在 application/libraies 目錄下存在 My_Email.php 時就能夠實現擴展類庫的功能。除了擴展以外,咱們還須要:php
1)直接覆蓋原始類app
2)徹底自定義類函數
很簡單,按照約定,當不存在MY_開頭的類庫文件,加載類庫的狀況一定屬於以上兩種,以下所示this
// 直接加載代碼 $is_duplicate = FALSE; foreach ($this->_ci_library_paths as $path) { $filepath = $path.'libraries/'.$subdir.$class.'.php'; if ( ! file_exists($filepath)) { continue; } if (in_array($filepath, $this->_ci_loaded_files)) { if ( ! is_null($object_name)) { $CI =& get_instance(); if ( ! isset($CI->$object_name)) { return $this->_ci_init_class($class, '', $params, $object_name); } } $is_duplicate = TRUE; log_message('debug', $class." class already loaded. Second attempt ignored."); return; } include_once($filepath); $this->_ci_loaded_files[] = $filepath; return $this->_ci_init_class($class, '', $params, $object_name); }
其中 _ci_libraries_path 在初始構造函數中初始化以下:spa
$this->_ci_library_paths = array(APPPATH, BASEPATH);
注意順序,先是 APPPATH, 而後再是 BASEPATH, 保證加載的順序先是 application ,再是 system。debug
再來看一下 _ci_init_class 函數設計
public function _ci_init_class($class, $prefix = '', $config = FALSE, $object_name = NULL) { if ($prefix == '') { if (class_exists('CI_'.$class)) { $name = 'CI_'.$class; } elseif (class_exists(config_item('subclass_prefix').$class)) { $name = config_item('subclass_prefix'); } else { $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); // 這裏對名字作了一個特殊的映射,針對 unit_test 就能夠直接用 unit, 而非 unit_test if (is_null($object_name)) { $classvar = ( ! isset($this->_ci_varmap[$class])) ? $class : $this->_ci_varmap[$class]; } else { $classvar = $object_name; } // 保存 class 名和對象名, 以供判斷某個類庫是否加載 $this->_ci_classes[$class] = $classvar; $CI =& get_instance(); if ($config !== NULL) { $CI->$classvar = new $name($config); } else { $CI->$classvar = new $name; }
分析以上代碼能夠發現,爲了直接覆蓋原始的類庫文件,對 $prefix ==‘’ 的狀況做了進一步處理,判斷是否存在 CI 或自定義MY_前綴的類,從而保證得到正確的類名。code
實例名也考慮到了一種特殊的狀況,好比加載 unit_test 類的時候,直接使用 unit 做爲變量,這也值得咱們借鑑和考慮!!!也就是說,在考慮到通常的狀況下,還能夠作更靈活的處理,對類名較長的類直接經過配置的方式指定實例名,很是簡潔~對象