一步一步重写 CodeIgniter 框架 (4) —— load_class 管理多个对象实例的思路

我们使用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!

posted @ 2013-07-11 00:25  风影无忌  阅读(5206)  评论(0编辑  收藏  举报