controller.php
1 <?php 2 class CI_Controller { 3 4 private static $instance; 5 6 public function __construct() 7 { 8 self::$instance =& $this; 9 10 foreach (is_loaded() as $var => $class) 11 { 12 $this->$var =& load_class($class); 13 $obj = $this->$var; 14 printf("var: |%s|, class: |%s|, obj: |%s|\n\n", $var, $class, var_export($obj, true)); 15 } 16 } 17 18 public static function &get_instance() 19 { 20 return self::$instance; 21 } 22 23 public function get() 24 { 25 require 'model.php'; 26 $model = new CI_Model(); 27 $str = $model -> invoteClass(); 28 return $str; 29 } 30 } 31 ?>
model.php
1 <?php 2 class CI_Model { 3 public function __construct() 4 { 5 } 6 7 /** 8 * 这个地方的__get魔术方法使用非常巧妙,值得研究一下 9 * 允许model层的类去访问对象$CI所指向的类中已经加载的类 10 * 11 * __get 12 * 13 * Allows models to access CI's loaded classes using the same 14 * syntax as controllers. 15 * 16 * @param string 17 * @access private 18 */ 19 public function __get($key) 20 { 21 $CI = &get_instance(); 22 printf("inner %s\n\n", __METHOD__); 23 return $CI->$key; 24 } 25 26 public function invoteClass() 27 { 28 //$this->appa调用魔术方法__get,魔术方法__get调用类CI_Controller中的成员变量appa 29 $obj = $this->appa; 30 echo 'inner ' . __METHOD__ . "\n\n"; 31 printf("obj is: |%s|\n\n", var_export($obj, true)); 32 printf("obj->getApp: %s\n\n", $obj->getApp()); 33 34 $obj = $this->appb; 35 echo 'inner ' . __METHOD__ . "\n\n"; 36 printf("obj is: |%s|\n\n", var_export($obj, true)); 37 printf("obj->getApp: %s\n\n", $obj->getApp()); 38 } 39 } 40 ?>
common.php
1 <?php 2 if ( ! function_exists('load_class')) 3 { 4 function &load_class($class) 5 { 6 static $_classes = array(); 7 8 // Does the class exist? If so, we're done... 9 // 如果要加载的类以前已经实例化过,则直接返回它 10 if (isset($_classes[$class])) 11 { 12 return $_classes[$class]; 13 } 14 15 if (file_exists($class.'.php')) 16 { 17 require($class.'.php'); 18 } 19 20 // Keep track of what we just loaded 21 //将所有加载过的类保存在静态数组_is_loaded中, 22 is_loaded($class); 23 24 //实例化类$name(比如CI_Input),然后将实例化后的类保存在静态变量$_classes中,避免下次重复实例化 25 $_classes[$class] = new $class(); 26 return $_classes[$class]; 27 } 28 } 29 30 // -------------------------------------------------------------------- 31 32 /** 33 * Keeps track of which libraries have been loaded. This function is 34 * called by the load_class() function above 35 * 36 * @access public 37 * @return array 38 */ 39 if ( ! function_exists('is_loaded')) 40 { 41 function &is_loaded($class = '') 42 { 43 static $_is_loaded = array(); 44 45 if ($class != '') 46 { 47 $_is_loaded[strtolower($class)] = $class; 48 } 49 50 return $_is_loaded; 51 } 52 } 53 54 function &get_instance() 55 { 56 return CI_Controller::get_instance(); 57 } 58 ?>
appa.php
1 <?php 2 class appA { 3 public function __construct() { 4 } 5 6 public function getApp() { 7 return 'this is appa'; 8 } 9 } 10 11 ?>
appb.php
1 <?php 2 class appB { 3 public function __construct() { 4 } 5 6 public function getApp() { 7 return 'this is appb'; 8 } 9 } 10 ?>
index.php
1 <?php 2 require 'controller.php'; 3 require 'common.php'; 4 5 load_class('appA'); 6 load_class('appB'); 7 $controller = new CI_Controller(); 8 echo 'inner ' . __FILE__ . "\n\n"; 9 $controller->get(); 10 ?>
运行php index.php输出结果如下:
E:\myphp\research\CodeIgniter_2.2.0\ci_study>php index.php
var: |appa|, class: |appA|, obj: |appA::__set_state(array(
))|
var: |appb|, class: |appB|, obj: |appB::__set_state(array(
))|
inner E:\myphp\research\CodeIgniter_2.2.0\ci_study\index.php
inner CI_Model::__get
inner CI_Model::invoteClass
obj is: |appA::__set_state(array(
))|
obj->getApp: this is appa
inner CI_Model::__get
inner CI_Model::invoteClass
obj is: |appB::__set_state(array(
))|
obj->getApp: this is appb
类CI_Model中并没有加载类appA与appB,确可以调用这两个类中的方法并取得数据,这里巧炒的采用了魔术方法__get的功能,并采用了单实例的设计模式实例了上述的调用过程,CI框架此处调用实在是巧炒,非常值得学习借鉴。