一步一步重寫 CodeIgniter 框架 (5) —— 實現Controller,並加載Model

 

CodeIgniter 框架採用MVC模式,而MVC模式中起紐帶做用的就是C(控制器),在控制器的中經過加載模型得到數據,將數據傳到視圖中進行展現。本課將實如今控制器中加載模型。php

 

1. 控制器的實現git

CodeIgniter 中控制器的做用很強大,經過繼承CI_Controller 類就能夠 $this->input 得到Input類的實例,其模型的調用方法是 $this->load->model('model'), 以後就能夠經過 $this->model_name->調用相應模型的方法獲取數據了。github

那麼如何實現的呢?請看 CodeIgniter 中 CI_Controller 的源碼。bootstrap

複製代碼

1 class CI_Controller {
 2 
 3     private static $instance;
 4 
 5     /**
 6      * Constructor
 7      */
 8     public function __construct()
 9     {
10         self::$instance =& $this;
11         
12         // Assign all the class objects that were instantiated by the
13         // bootstrap file (CodeIgniter.php) to local class variables
14         // so that CI can run as one big super object.
15         foreach (is_loaded() as $var => $class)
16         {
17             $this->$var =& load_class($class);
18         }
19 
20         $this->load =& load_class('Loader', 'core');
21 
22         $this->load->initialize();
23         
24         log_message('debug', "Controller Class Initialized");
25     }
26 
27     public static function &get_instance()
28     {
29         return self::$instance;
30     }
31 }

複製代碼

它定義了一個靜態成員變量,並在初始化時等於本身 self::$instance =& $this; 而後就能夠經過 get_instance 靜態函數得到該實例。數組

foreach 循環將 經過 load_class 函數管理的實例對象(很是重要的對象,如Input,Output等)賦值做爲該類的成員變量,也就是說 $this->input 至關於 load_class('Input‘)。全部控制器類經過繼承 Controller 基類,就能夠一樣得到這種便利!!框架

值得注意的是,與其餘核心類不一樣, Loader  類是在這裏的構造函數處進行的,說明了 Loader  類對於 Controller 的重要性。函數

$this->load =& load_class('Loader', 'core'); 測試

2. Loader 類的 model 實現ui

Loader 類管理的 model 會比較多,上節課着重講了 load_class 這種管理多個實例的原理,如下 model 函數就不難理解。this

按照 CodeIgniter 的管理,通常會定義幾個搜索路徑,因此能夠在 Loader 中定義兩個變量

protected $_ci_model_paths = array();

    protected $_ci_models = array();

其中 $_ci_model_paths 表明路徑, $_ci_models 表明已加載的模型。

在構造函數中,將$_ci_model_paths 初始化爲 APPPATH,因爲在本課中尚未分層,APPPATH 等同於當前目錄,讓 $_ci_model_paths = array('');

 

而後定義 model 函數

複製代碼

public function model($model, $name = '', $db_conn = FALSE) {

        if (is_array($model)) {
            foreach ($model as $babe) {
                $this->model($babe);
            }
            return;
        }

        if ($model == '') {
            return;
        }

        // model 是否在一個文件夾中,若是是的話,則分析路徑和文件名
        if (($last_slash = strrpos($model, '/')) !== FALSE) {
            $path = substr($model, 0, $last_slash + 1);

            $model = substr($model, $last_slash + 1);
        }

        if ($name = '') {
            $name = $model;
        }

        if (in_array($name, $this->_ci_models, TRUE)) {
            return;
        }

        $CI =& get_instance();
        if (isset($CI->$name)) {
            show_error('The model name you are loading is the name of a resource that is already being used: '.$name);
        }

        $model = strtolower($model);

        foreach ($this->_ci_model_paths as $mod_path) {
            if ( ! file_exists($mod_path.'models/'.$path.$model.'.php')) {
                continue;
            }

            if ($db_conn !== FALSE AND ! class_exists('CI_DB')) {
                if ($db_conn === TRUE) {
                    $db_conn = '';
                }

                $CI->load->database($db_conn, FALSE, TRUE);
            }

            if ( ! class_exists('CI_Model')) {
                load_class('Model', 'core');
            }

            require_once($mod_path.'models/'.$path.$model.'.php');
            $model = ucfirst($model);

            $CI->$name = new $model();

            $this->_ci_models[] = $name;
            return;
        }

        // 找不到模型
        exit('Unable to locate the model you have specified: '.$model);

    }

複製代碼

1)經過 is_array 判斷參數是否爲數組,是的話,循環加載每個模型,這樣就能夠經過傳遞數組一次加載多個模型。(這也是一個很好的技巧哦,傳參數的時候就能夠既傳單個值,也能夠傳數組)

2)model 能夠包含路徑,這樣更利於 model 的組織,好比用戶模塊的 基本信息model, 積分 model 均可以放在 user 文件夾下,因此將路徑按 '/' 拆分,就能夠獲得二級 path 和 model 名。

3)加載 model 後,該model 實例會做爲 $this 的成員變量,用什麼標識呢?若是不提供的話,默認就用 model 的名字。

   好比  $this->load->model('news_model');

  加載後,能夠經過 $this->news_model 來訪問加載的模型。

4)規範化

  $this->load->model('News_model’); 這個用戶想加載的類與 3)中一致,因此 $model 都會 strtolower 小寫統一標記,這樣不會出現兩次加載了,另外實際在定義類的時候,news_model 對應的 class News_model;

  經過參考這些,咱們能夠提升寫代碼的優美度,也就是說用戶可能在誤輸入大小寫的狀況下,依然保證能獲得預期的效果。

 

3. 測試

  根據前述講述,針對上一節的代碼,本次新加入的代碼包括 Loader.php , Controller.php, Model.php( 暫時爲空)

  Welcome 類要繼承 CI_Controller 類以下所示(放在 controllers 目錄下)

複製代碼

<?php

class welcome extends CI_Controller {

    function hello() {
        echo 'My first Php Framework!';
    }

    function saysomething($str) {
        $this->load->model('test_model');

        $info = $this->test_model->get_test_data();

        echo $info;
    }
}

複製代碼

爲了測試 model 新建一個 models/test_model.php 文件,而後寫入

複製代碼

<?php

class Test_model extends CI_Model {


    function get_test_data() {
        return 'People you want in our model is Zhangzhenyu';
    }


}

複製代碼

其中 CI_Model 暫時能夠爲空, 在 core/Model.php 下定義一個 CI_Model 的空類便可,以保證程序的正確執行。

 

主執行文件也須要作相應的更改以下:

複製代碼

require('core/Controller.php');

function &get_instance() {
    return CI_Controller::get_instance();
}



require('controllers/'.$class.'.php');


$CI = new $class();

call_user_func_array(array(&$CI, $method), array_slice($URI->rsegments, 2));

複製代碼

4. 測試結果

訪問 http://localhost/learn-ci/index.php/welcome/hello

輸出 People you want in our model is Zhangzhenyu

 

具體代碼參見 https://github.com/zhenyu-whu/learn-ci

相關文章
相關標籤/搜索