我們使用CodeIgniter 框架最主要是想利用其 MVC 特性,將模型、視圖分開,並通過控制器進行統一控制。在嘗試實現 MVC 模式之前,我們將實現其中一個對程序結構非常有用的技巧,就是 load_class 函數。
在上一課中,我們用面向對象的方法大大簡化了程序的結構,將主要工作放在兩個類中進行 ,URI 和 Router 類。 但是在 Router 類的構造函數中為了獲得 uri 的實例,我們使用了 global 關鍵字,如下所示:
1 class CI_Router { 2 ... 3 function __construct() { 4 global $URI; 5 $this->uri = &$URI; 6 } 7 .... 8 }
當程序的結構變得很復雜時,用 global 關鍵詞會使得全局變量的管理非常亂,而且這些全局變量往往對應於一個具體功能類的實例,在實例化之前需要加載相應class的 php 文件。
1. 問題提煉和分析
根據上述分析,關鍵的問題是
1)需要一個集成管理這些全局變量的地方
2)這些類的實例產生時,很方便的加載對應的 php 文件。
集成管理變量一般采用 類的方式,然后通過該類的一個實例(唯一一個)獲取需要的變量,這個實例往往稱為核心全局變量,如discuz 中的 $discuz_core 變量;
另一種方式,就是函數,但是函數沒法存儲成員變量,所以必須利用一個很有用的語法特性,就是 static 靜態變量。
在這里,我們采用第二種更簡潔的方式。
2. 實現步驟
1) 定義函數的接口
函數名為 load_class , 我們希望通過傳遞一個字符串參數,就能獲得對應的實例,比如 load_class('Router'); 就可以得到 上一課中的 $RTR 變量的引用。
所以函數的接口為:
function &load_class($class) {}
2) 定義存儲這些重要類實例全局變量的靜態數組
static $_classes = array();
那么該數組,存儲的鍵值對就是 ’Router' => $RTR 的樣子。
3) 具體的邏輯
1 // 當加載需要的類實例時,如果不是第一次加載,那么 $_classes 數組中肯定存放了需要的實例,直接返回即可 2 if (isset($_classes[$class])) { 3 return $_classes[$class]; 4 } 5 6 // 在我們的框架中,每個類實例都有前綴CI_ 7 $name = 'CI_'.$class; 8 9 if (file_exists($class.'.php')) { 10 require($class.'.php'); 11 } else { 12 exit('Unable to locate the class'); 13 } 14 15 $_classes[$class] = new $name(); 16 return $_classes[$class];
3. 修改主邏輯代碼
1 <?php 2 /** 3 * 框架主入口文件,所有的頁面請求均定為到該頁面,並根據 url 地址來確定調用合適的方法並顯示輸出 4 */ 5 require('Common.php'); 6 7 $URI =& load_class('URI'); 8 $RTR =& load_class('Router'); 9 10 $RTR->set_routing(); 11 12 13 $class = $RTR->fetch_class(); 14 $method = $RTR->fetch_method(); 15 16 $CI = new $class(); 17 18 call_user_func_array(array(&$CI, $method), array_slice($URI->rsegments, 2)); 19 20 class Welcome { 21 22 function hello() { 23 echo 'My first Php Framework!'; 24 } 25 26 function saysomething($str) { 27 echo $str.", I'am the php framework you created!"; 28 } 29 }
另外,所有需要用到這些全局變量的地方,調用 load_class 就可以了,所以 Router 構造函數的地方使用 load_class.
1 function __construct() { 2 $this->uri =& load_class('URI'); 3 }
4. 測試結果
訪問 http://localhost/learn-ci/index.php/welcome/hello , 可以看到輸出為:
hello, I'am the php framework you created!