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


通過前面幾節的內容,我們從零開始搭建了一個非常方便的MVC框架,理解了 CodeIgniter 框架最核心的部分。然而一個框架的便利不僅僅在於提供一個MVC就可以了,它還必須具有較高的擴展性。下面將從 CodeIgniter 的官方文檔中的順序一步一步充實我們這個“丑陋” 的框架。

本課將實現 CodeIgniter 類庫加載的模式,對應於http://codeigniter.org.cn/user_guide/general/libraries.html

 

1. library 函數

首先類庫加載設計在 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 類似,它首先判斷傳入的第一個參數是否為數組,如果是的話,就遞歸調用一次。

它通過調用 _ci_load_class 函數來實際加載具體的類。

 2. _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 的思路,首先會對加載函數的第一個參數路徑進行拆分,得到具體的路徑和文件名,因為文件名會有一些特殊的約定。

CodeIgniter 在設計的時候有個很重要的思想,就是區分 system 和 application 兩種類型的代碼,從而設計出靈活性很高的框架,那么針對 類庫 而言,就是在 system 中提供一些常用的類庫,然后給用戶在這個基礎上擴展或覆蓋的權利,另外,也可以直接在 

application 文件夾下設計出完全自定義的類。

本節主要實現 在原有類上進行擴展 的代碼

1) 首先判斷 application 文件夾下是否存在按照約定命名的擴展類庫文件,即 subclass_prefix = 'MY_', 就判斷是否存在 MY_類庫名.php 文件

2)如果存在,則加載基類庫文件,全部 include 之后,就可以 _ci_init_class 了

3. _ci_init_class 實例化 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->函數名();


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM