一步一步重寫 CodeIgniter 框架 (10) —— 使用 CodeIgniter 類庫(續)

上一節簡單實現了 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 做爲變量,這也值得咱們借鑑和考慮!!!也就是說,在考慮到通常的狀況下,還能夠作更靈活的處理,對類名較長的類直接經過配置的方式指定實例名,很是簡潔~對象

 

總結: 整個過程加載類庫的設計就完成了,特別靈活和方便。

相關文章
相關標籤/搜索