| //*BASEPATH/system/core/Common.php //引導檔案中Benchmark,Hooks,Config等都是通過這個函數進行載入的 function &load_class($class, $directory = 'libraries', $prefix = 'CI_') { //記錄載入過的類 static $_classes = array(); // 已經載入過,直接讀取並返回 if (isset($_classes[$class])) { return $_classes[$class]; } $name = FALSE; // 在指定目錄尋找要載入的類 foreach (array(APPPATH, BASEPATH) as $path) { if (file_exists($path.$directory.'/'.$class.'.php')) { $name = $prefix.$class; if (class_exists($name) === FALSE) { require($path.$directory.'/'.$class.'.php'); } break; } } // 沒有找到 if ($name === FALSE) { exit('Unable to locate the specified class: '.$class.'.php'); } // 追蹤記錄下剛才載入的類,is_loaded()函數在下面 is_loaded($class); $_classes[$class] = new $name(); return $_classes[$class]; } // 記錄已經載入過的類。函數返回所有載入過的類 function &is_loaded($class = '') { static $_is_loaded = array(); if ($class != '') { $_is_loaded[strtolower($class)] = $class; } return $_is_loaded; } //*BASEPATH/system/core/Controller.php class CI_Controller { private static $instance; public function __construct() { self::$instance =& $this; //將所有在引導檔案中(CodeIgniter.php)初始化的類對象(即剛才4,5,6,7,8,9等步驟), //註冊成為控制器類的成員變數,就使得這個控制器成為一個超級對象(super object) foreach (is_loaded() as $var => $class) { $this->$var =& load_class($class); } //載入Loader對象,再利用Loader對象對程式內一系列資源進行載入 $this->load =& load_class('Loader', 'core'); $this->load->initialize(); log_message('debug', "Controller Class Initialized"); } //這個函數對外提供了控制器的單一執行個體 public static function &get_instance() { return self::$instance; } } //*BASEPATH/system/core/CodeIgniter.php // Load the base controller class require BASEPATH.'core/Controller.php'; //通過這個全域函數就得到了控制器的執行個體,得到了這個超級對象, //意味著在程式其他地方調用這個函數,就能得到整個架構的控制權 function &get_instance() { return CI_Controller::get_instance(); } // 載入對應的控制器類 // 注意:Router類會自動使用 router->_validate_request() 驗證控制器路徑 if ( ! file_exists(APPPATH.'controllers/'.$RTR->fetch_directory().$RTR->fetch_class().'.php')) { show_error('Unable to load your default controller. Please make sure the controller specified in your Routes.php file is valid.'); } include(APPPATH.'controllers/'.$RTR->fetch_directory().$RTR->fetch_class().'.php'); $class = $RTR->fetch_class(); //Controller class name $method = $RTR->fetch_method(); //action name //..... // 調用請求的函數 // uri中除了class/function之外的段也會被傳遞給調用的函數 call_user_func_array(array(&$CI, $method), array_slice($URI->rsegments, 2)); //輸出最終的內容到瀏覽器 if ($EXT->_call_hook('display_override') === FALSE) { $OUT->_display(); } //*BASEPATH/system/core/Loader.php //看一個Loader類載入model的例子。這裡只列出了部分代碼 public function model($model, $name = '', $db_conn = FALSE) { $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); //依次根據model類的path進行匹配,如果找到了就載入 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); //這裡依然將model對象註冊成控制器類的成員變數。Loader在載入其他資源的時候也會這麼做 $CI->$name = new $model(); $this->_ci_models[] = $name; return; } // couldn't find the model show_error('Unable to locate the model you have specified: '.$model); } //*BASEPATH/system/core/Model.php //__get()是一個魔術方法,當讀取一個未定義的變數的值時就會被調用 //如下是Model基類對__get()函數的一個實現,使得在Model類內,可以像直接在控制器類內一樣(例如$this->var的方式)去讀取它的變數 function __get($key) { $CI =& get_instance(); return $CI->$key; |