一步一步重写 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!