Heim >php教程 >php手册 >CI加载流程小结,ci加载小结

CI加载流程小结,ci加载小结

WBOY
WBOYOriginal
2016-06-13 09:12:401258Durchsuche

CI加载流程小结,ci加载小结

  无聊,决定水一把。

  CI(CodeIgniter)是我最早接触的一个框架,到现在也只是用了其中一点零碎的方法。一直想对其流程做个小结,却总是因各种各样的“理由”挨着。看见别人图表齐上阵,没那耐心,就从代码说起吧,权当做个笔记,纪念一下。

  看在线的用户手册,也知道,将CI下载下来(最新版本2.2.1),解压到机子上,比如www目录,可改个根目录名(原名CodeIgniter-2.2-stable太长),初步目录文件如下,当然这在是windows下面。

     

      访问下,如localhost/ci/index.php,就进入CI默认的Welcome页面

  

  如何一步步加载这个页面的?首先访问的是index.php脚本

1 php 2 3 /* 4 *--------------------------------------------------------------- 5 * APPLICATION ENVIRONMENT 6 *--------------------------------------------------------------- 7 * 8 * You can load different configurations depending on your 9 * current environment. Setting the environment also influences 10 * things like logging and error reporting. 11 * 12 * This can be set to anything, but default usage is: 13 * 14 * development 15 * testing 16 * production 17 * 18 * NOTE: If you change these, also change the error_reporting() code below 19 * 20 */ 21 define('ENVIRONMENT', 'development'); 22 /* 23 *--------------------------------------------------------------- 24 * ERROR REPORTING 25 *--------------------------------------------------------------- 26 * 27 * Different environments will require different levels of error reporting. 28 * By default development will show errors but testing and live will hide them. 29 */ 30 31 if (defined('ENVIRONMENT')) 32 { 33 switch (ENVIRONMENT) 34 { 35 case 'development': 36 error_reporting(E_ALL); 37 break; 38 39 case 'testing': 40 case 'production': 41 error_reporting(0); 42 break; 43 44 default: 45 exit('The application environment is not set correctly.'); 46 } 47 } 48 49 /* 50 *--------------------------------------------------------------- 51 * SYSTEM FOLDER NAME 52 *--------------------------------------------------------------- 53 * 54 * This variable must contain the name of your "system" folder. 55 * Include the path if the folder is not in the same directory 56 * as this file. 57 * 58 */ 59 $system_path = 'system'; 60 61 /* 62 *--------------------------------------------------------------- 63 * APPLICATION FOLDER NAME 64 *--------------------------------------------------------------- 65 * 66 * If you want this front controller to use a different "application" 67 * folder then the default one you can set its name here. The folder 68 * can also be renamed or relocated anywhere on your server. If 69 * you do, use a full server path. For more info please see the user guide: 70 * http://codeigniter.com/user_guide/general/managing_apps.html 71 * 72 * NO TRAILING SLASH! 73 * 74 */ 75 $application_folder = 'application'; 76 77 /* 78 * -------------------------------------------------------------------- 79 * DEFAULT CONTROLLER 80 * -------------------------------------------------------------------- 81 * 82 * Normally you will set your default controller in the routes.php file. 83 * You can, however, force a custom routing by hard-coding a 84 * specific controller class/function here. For most applications, you 85 * WILL NOT set your routing here, but it's an option for those 86 * special instances where you might want to override the standard 87 * routing in a specific front controller that shares a common CI installation. 88 * 89 * IMPORTANT: If you set the routing here, NO OTHER controller will be 90 * callable. In essence, this preference limits your application to ONE 91 * specific controller. Leave the function name blank if you need 92 * to call functions dynamically via the URI. 93 * 94 * Un-comment the $routing array below to use this feature 95 * 96 */ 97 // The directory name, relative to the "controllers" folder. Leave blank 98 // if your controller is not in a sub-folder within the "controllers" folder 99 // $routing['directory'] = ''; 100 101 // The controller class file name. Example: Mycontroller 102 // $routing['controller'] = ''; 103 104 // The controller function you wish to be called. 105 // $routing['function'] = ''; 106 107 108 /* 109 * ------------------------------------------------------------------- 110 * CUSTOM CONFIG VALUES 111 * ------------------------------------------------------------------- 112 * 113 * The $assign_to_config array below will be passed dynamically to the 114 * config class when initialized. This allows you to set custom config 115 * items or override any default config values found in the config.php file. 116 * This can be handy as it permits you to share one application between 117 * multiple front controller files, with each file containing different 118 * config values. 119 * 120 * Un-comment the $assign_to_config array below to use this feature 121 * 122 */ 123 // $assign_to_config['name_of_config_item'] = 'value of config item'; 124 125 126 127 // -------------------------------------------------------------------- 128 // END OF USER CONFIGURABLE SETTINGS. DO NOT EDIT BELOW THIS LINE 129 // -------------------------------------------------------------------- 130 131 /* 132 * --------------------------------------------------------------- 133 * Resolve the system path for increased reliability 134 * --------------------------------------------------------------- 135 */ 136 137 // Set the current directory correctly for CLI requests 138 if (defined('STDIN')) 139 { 140 chdir(dirname(__FILE__)); 141 } 142 143 if (realpath($system_path) !== FALSE) 144 { 145 $system_path = realpath($system_path).'/'; 146 } 147 148 // ensure there's a trailing slash 149 $system_path = rtrim($system_path, '/').'/'; 150 151 // Is the system path correct? 152 if ( ! is_dir($system_path)) 153 { 154 exit("Your system folder path does not appear to be set correctly. Please open the following file and correct this: ".pathinfo(__FILE__, PATHINFO_BASENAME)); 155 } 156 157 /* 158 * ------------------------------------------------------------------- 159 * Now that we know the path, set the main path constants 160 * ------------------------------------------------------------------- 161 */ 162 // The name of THIS file 163 define('SELF', pathinfo(__FILE__, PATHINFO_BASENAME)); 164 165 // The PHP file extension 166 // this global constant is deprecated. 167 define('EXT', '.php'); 168 169 // Path to the system folder 170 define('BASEPATH', str_replace("\\", "/", $system_path)); 171 172 // Path to the front controller (this file) 173 define('FCPATH', str_replace(SELF, '', __FILE__)); 174 175 // Name of the "system folder" 176 define('SYSDIR', trim(strrchr(trim(BASEPATH, '/'), '/'), '/')); 177 178 179 // The path to the "application" folder 180 if (is_dir($application_folder)) 181 { 182 define('APPPATH', $application_folder.'/'); 183 } 184 else 185 { 186 if ( ! is_dir(BASEPATH.$application_folder.'/')) 187 { 188 exit("Your application folder path does not appear to be set correctly. Please open the following file and correct this: ".SELF); 189 } 190 191 define('APPPATH', BASEPATH.$application_folder.'/'); 192 } 193 194 /* 195 * -------------------------------------------------------------------- 196 * LOAD THE BOOTSTRAP FILE 197 * -------------------------------------------------------------------- 198 * 199 * And away we go... 200 * 201 */ 202 require_once BASEPATH.'core/CodeIgniter.php'; 203 204 /* End of file index.php */ 205 /* Location: ./index.php */ View Code

  21行:首先定义一个ENVIRONMENT常量为development,即开发环境。

  31-47行:switch语句,由于当前环境是development,所以是设置报告所有级别的错误。

  49-59行:$system_path变量定义CI的默认的系统脚本目录是 system,61-75行定义当前默认的供我们主要开发用的目录为 application。

  77-105行:全部注释掉了,这里是我们可以强制设置系统加载时默认的目录名($routing['directory'])、控制器名($routing['directory'])和方法名($routing['directory']),虽然一般这些是设置在application\config\routes.php中(下图),访问的Welcome页面也是通过这个默认控制器Welcome类进行的,这里只是作为一个选择性的方式,其实没必要弄

     

  108-129行:全部注释掉,用于自定义配置变量(CUSTOM CONFIG VALUES),前一篇说过,任何后端project中,总有些配置信息,只是各个项目或框架加载方式不同,这个$assign_to_config数组就存放我们的自定义配置信息,如$assign_to_config['home'] = 'localhost'; ,之所以注释掉,又是因为这只是一个可选的操作,CI的用户自定义配置信息,一般放在application\config目录下边,以自动加载信息(autoload.php),普通配置信息(config.php)、常量(constants.php)、数据库(database.php)等分开文件存储,所以一般不会在这里的去配置一个要用到的变量,$assign_to_config默认是没有定义的。

     

   从131行到index.php文件末尾主要是对一些路径变量的定义。

  137-141行:是为CLI(Command-Interface Line)的调用方式准备的,是直接在Mac/Linux系统上通过终端命令运行脚本,这个在CI中文官网(http://codeigniter.org.cn/user_guide/general/cli.html)也有介绍,如果定义了名为STDIN的常量,则将执行目录改为当前文件所在目录,当然前面没有出现过STDIN这个常量的定义,这里就不会执行了。

     

  143-155行:确定框架存放系统脚本的目录变量$system_path,也就是前面图中的system目录,这里会检测它的有效性,无效的话程序就挂在这里了。

  157-192行:定义若干主要目录常量,分别是SELF:当前脚本的文件名、EXT:脚本扩展名、BASEPATH:system目录的路径、FCPATH:当前脚本所在的目录、SYSDIR:system目录的目录名,不改动的话就是system。

  179-194行:定义APPPATH常量,确定application所在的目录,就是以后我们主要开发的地方,使用is_dir检测,稍微注意的是is_dir可以检测相对目录,所以实际运行的是if里边的代码,APPPATH得到的是相对路径。

  最后打印看看这些变(常)量的值都是啥,有的与存放目录相关:

  

  202行:加载BASEPATH.'core/CodeIgniter.php'脚本,就是system目录下的核心类文件目录下的文件,进入到CI的核心类目录下的文件了。

=====================================================================================================

1 if ( ! defined('BASEPATH')) exit('No direct script access allowed'); 2 /** 3 * CodeIgniter 4 * 5 * An open source application development framework for PHP 5.1.6 or newer 6 * 7 * @package CodeIgniter 8 * @author EllisLab Dev Team 9 * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. 10 * @copyright Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/) 11 * @license http://codeigniter.com/user_guide/license.html 12 * @link http://codeigniter.com 13 * @since Version 1.0 14 * @filesource 15 */ 16 17 // ------------------------------------------------------------------------ 18 19 /** 20 * System Initialization File 21 * 22 * Loads the base classes and executes the request. 23 * 24 * @package CodeIgniter 25 * @subpackage codeigniter 26 * @category Front-controller 27 * @author EllisLab Dev Team 28 * @link http://codeigniter.com/user_guide/ 29 */ 30 31 /** 32 * CodeIgniter Version 33 * 34 * @var string 35 * 36 */ 37 define('CI_VERSION', '2.2.1'); 38 39 /** 40 * CodeIgniter Branch (Core = TRUE, Reactor = FALSE) 41 * 42 * @var boolean 43 * 44 */ 45 define('CI_CORE', FALSE); 46 47 /* 48 * ------------------------------------------------------ 49 * Load the global functions 50 * ------------------------------------------------------ 51 */ 52 require(BASEPATH.'core/Common.php'); 53 54 /* 55 * ------------------------------------------------------ 56 * Load the framework constants 57 * ------------------------------------------------------ 58 */ 59 if (defined('ENVIRONMENT') AND file_exists(APPPATH.'config/'.ENVIRONMENT.'/constants.php')) 60 { 61 require(APPPATH.'config/'.ENVIRONMENT.'/constants.php'); 62 } 63 else 64 { 65 require(APPPATH.'config/constants.php'); 66 } 67 68 /* 69 * ------------------------------------------------------ 70 * Define a custom error handler so we can log PHP errors 71 * ------------------------------------------------------ 72 */ 73 set_error_handler('_exception_handler'); 74 75 if ( ! is_php('5.3')) 76 { 77 @set_magic_quotes_runtime(0); // Kill magic quotes 78 } 79 80 /* 81 * ------------------------------------------------------ 82 * Set the subclass_prefix 83 * ------------------------------------------------------ 84 * 85 * Normally the "subclass_prefix" is set in the config file. 86 * The subclass prefix allows CI to know if a core class is 87 * being extended via a library in the local application 88 * "libraries" folder. Since CI allows config items to be 89 * overriden via data set in the main index. php file, 90 * before proceeding we need to know if a subclass_prefix 91 * override exists. If so, we will set this value now, 92 * before any classes are loaded 93 * Note: Since the config file data is cached it doesn't 94 * hurt to load it here. 95 */ 96 if (isset($assign_to_config['subclass_prefix']) AND $assign_to_config['subclass_prefix'] != '') 97 { 98 get_config(array('subclass_prefix' => $assign_to_config['subclass_prefix'])); 99 } 100 101 /* 102 * ------------------------------------------------------ 103 * Set a liberal script execution time limit 104 * ------------------------------------------------------ 105 */ 106 if (function_exists("set_time_limit") == TRUE AND @ini_get("safe_mode") == 0) 107 { 108 @set_time_limit(300); 109 } 110 111 /* 112 * ------------------------------------------------------ 113 * Start the timer... tick tock tick tock... 114 * ------------------------------------------------------ 115 */ 116 $BM =& load_class('Benchmark', 'core'); 117 $BM->mark('total_execution_time_start'); 118 $BM->mark('loading_time:_base_classes_start'); 119 120 /* 121 * ------------------------------------------------------ 122 * Instantiate the hooks class 123 * ------------------------------------------------------ 124 */ 125 $EXT =& load_class('Hooks', 'core'); 126 127 /* 128 * ------------------------------------------------------ 129 * Is there a "pre_system" hook? 130 * ------------------------------------------------------ 131 */ 132 $EXT->_call_hook('pre_system'); 133 134 /* 135 * ------------------------------------------------------ 136 * Instantiate the config class 137 * ------------------------------------------------------ 138 */ 139 $CFG =& load_class('Config', 'core'); 140 141 // Do we have any manually set config items in the index.php file? 142 if (isset($assign_to_config)) 143 { 144 $CFG->_assign_to_config($assign_to_config); 145 } 146 147 /* 148 * ------------------------------------------------------ 149 * Instantiate the UTF-8 class 150 * ------------------------------------------------------ 151 * 152 * Note: Order here is rather important as the UTF-8 153 * class needs to be used very early on, but it cannot 154 * properly determine if UTf-8 can be supported until 155 * after the Config class is instantiated. 156 * 157 */ 158 159 $UNI =& load_class('Utf8', 'core'); 160 161 /* 162 * ------------------------------------------------------ 163 * Instantiate the URI class 164 * ------------------------------------------------------ 165 */ 166 $URI =& load_class('URI', 'core'); 167 168 /* 169 * ------------------------------------------------------ 170 * Instantiate the routing class and set the routing 171 * ------------------------------------------------------ 172 */ 173 $RTR =& load_class('Router', 'core'); 174 $RTR->_set_routing(); 175 176 // Set any routing overrides that may exist in the main index file 177 if (isset($routing)) 178 { 179 $RTR->_set_overrides($routing); 180 } 181 182 /* 183 * ------------------------------------------------------ 184 * Instantiate the output class 185 * ------------------------------------------------------ 186 */ 187 $OUT =& load_class('Output', 'core'); 188 189 /* 190 * ------------------------------------------------------ 191 * Is there a valid cache file? If so, we're done... 192 * ------------------------------------------------------ 193 */ 194 if ($EXT->_call_hook('cache_override') === FALSE) 195 { 196 if ($OUT->_display_cache($CFG, $URI) == TRUE) 197 { 198 exit; 199 } 200 } 201 202 /* 203 * ----------------------------------------------------- 204 * Load the security class for xss and csrf support 205 * ----------------------------------------------------- 206 */ 207 $SEC =& load_class('Security', 'core'); 208 209 /* 210 * ------------------------------------------------------ 211 * Load the Input class and sanitize globals 212 * ------------------------------------------------------ 213 */ 214 $IN =& load_class('Input', 'core'); 215 216 /* 217 * ------------------------------------------------------ 218 * Load the Language class 219 * ------------------------------------------------------ 220 */ 221 $LANG =& load_class('Lang', 'core'); 222 223 /* 224 * ------------------------------------------------------ 225 * Load the app controller and local controller 226 * ------------------------------------------------------ 227 * 228 */ 229 // Load the base controller class 230 require BASEPATH.'core/Controller.php'; 231 232 function &get_instance() 233 { 234 return CI_Controller::get_instance(); 235 } 236 237 238 if (file_exists(APPPATH.'core/'.$CFG->config['subclass_prefix'].'Controller.php')) 239 { 240 require APPPATH.'core/'.$CFG->config['subclass_prefix'].'Controller.php'; 241 } 242 243 // Load the local application controller 244 // Note: The Router class automatically validates the controller path using the router->_validate_request(). 245 // If this include fails it means that the default controller in the Routes.php file is not resolving to something valid. 246 if ( ! file_exists(APPPATH.'controllers/'.$RTR->fetch_directory().$RTR->fetch_class().'.php')) 247 { 248 show_error('Unable to load your default controller. Please make sure the controller specified in your Routes.php file is valid.'); 249 } 250 251 include(APPPATH.'controllers/'.$RTR->fetch_directory().$RTR->fetch_class().'.php'); 252 253 // Set a mark point for benchmarking 254 $BM->mark('loading_time:_base_classes_end'); 255 256 /* 257 * ------------------------------------------------------ 258 * Security check 259 * ------------------------------------------------------ 260 * 261 * None of the functions in the app controller or the 262 * loader class can be called via the URI, nor can 263 * controller functions that begin with an underscore 264 */ 265 $class = $RTR->fetch_class(); 266 $method = $RTR->fetch_method(); 267 268 if ( ! class_exists($class) 269 OR strncmp($method, '_', 1) == 0 270 OR in_array(strtolower($method), array_map('strtolower', get_class_methods('CI_Controller'))) 271 ) 272 { 273 if ( ! empty($RTR->routes['404_override'])) 274 { 275 $x = explode('/', $RTR->routes['404_override']); 276 $class = $x[0]; 277 $method = (isset($x[1]) ? $x[1] : 'index'); 278 if ( ! class_exists($class)) 279 { 280 if ( ! file_exists(APPPATH.'controllers/'.$class.'.php')) 281 { 282 show_404("{$class}/{$method}"); 283 } 284 285 include_once(APPPATH.'controllers/'.$class.'.php'); 286 } 287 } 288 else 289 { 290 show_404("{$class}/{$method}"); 291 } 292 } 293 294 /* 295 * ------------------------------------------------------ 296 * Is there a "pre_controller" hook? 297 * ------------------------------------------------------ 298 */ 299 $EXT->_call_hook('pre_controller'); 300 301 /* 302 * ------------------------------------------------------ 303 * Instantiate the requested controller 304 * ------------------------------------------------------ 305 */ 306 // Mark a start point so we can benchmark the controller 307 $BM->mark('controller_execution_time_( '.$class.' / '.$method.' )_start'); 308 309 $CI = new $class(); 310 311 /* 312 * ------------------------------------------------------ 313 * Is there a "post_controller_constructor" hook? 314 * ------------------------------------------------------ 315 */ 316 $EXT->_call_hook('post_controller_constructor'); 317 318 /* 319 * ------------------------------------------------------ 320 * Call the requested method 321 * ------------------------------------------------------ 322 */ 323 // Is there a "remap" function? If so, we call it instead 324 if (method_exists($CI, '_remap')) 325 { 326 $CI->_remap($method, array_slice($URI->rsegments, 2)); 327 } 328 else 329 { 330 // is_callable() returns TRUE on some versions of PHP 5 for private and protected 331 // methods, so we'll use this workaround for consistent behavior 332 if ( ! in_array(strtolower($method), array_map('strtolower', get_class_methods($CI)))) 333 { 334 // Check and see if we are using a 404 override and use it. 335 if ( ! empty($RTR->routes['404_override'])) 336 { 337 $x = explode('/', $RTR->routes['404_override']); 338 $class = $x[0]; 339 $method = (isset($x[1]) ? $x[1] : 'index'); 340 if ( ! class_exists($class)) 341 { 342 if ( ! file_exists(APPPATH.'controllers/'.$class.'.php')) 343 { 344 show_404("{$class}/{$method}"); 345 } 346 347 include_once(APPPATH.'controllers/'.$class.'.php'); 348 unset($CI); 349 $CI = new $class(); 350 } 351 } 352 else 353 { 354 show_404("{$class}/{$method}"); 355 } 356 } 357 358 // Call the requested method. 359 // Any URI segments present (besides the class/function) will be passed to the method for convenience 360 call_user_func_array(array(&$CI, $method), array_slice($URI->rsegments, 2)); 361 } 362 363 364 // Mark a benchmark end point 365 $BM->mark('controller_execution_time_( '.$class.' / '.$method.' )_end'); 366 367 /* 368 * ------------------------------------------------------ 369 * Is there a "post_controller" hook? 370 * ------------------------------------------------------ 371 */ 372 $EXT->_call_hook('post_controller'); 373 374 /* 375 * ------------------------------------------------------ 376 * Send the final rendered output to the browser 377 * ------------------------------------------------------ 378 */ 379 if ($EXT->_call_hook('display_override') === FALSE) 380 { 381 $OUT->_display(); 382 } 383 384 /* 385 * ------------------------------------------------------ 386 * Is there a "post_system" hook? 387 * ------------------------------------------------------ 388 */ 389 $EXT->_call_hook('post_system'); 390 391 /* 392 * ------------------------------------------------------ 393 * Close the DB connection if one exists 394 * ------------------------------------------------------ 395 */ 396 if (class_exists('CI_DB') AND isset($CI->db)) 397 { 398 $CI->db->close(); 399 } 400 401 402 /* End of file CodeIgniter.php */ 403 /* Location: ./system/core/CodeIgniter.php */ View Code

  在CodeIgniter中,可以看到开头的英文描述,该脚本时系统初始化文件,主要作用是装载基类和执行请求。

  31-45行:定义了CI_VERSION常量,描述当前框架版本,CI_CORE常量,目前我也不清楚没探究过,注释是CI的分支,啥意思?

  52行:加载系统核心目录下的Common.php文件,Load the global functions,记得前一篇中说到,一般一个项目会将很多公共方法放在一个脚本中加载进来,通常取名Utilities.php,也可是Common.php,这里的Common.php也是这个意思,如它的解释是“加载全局函数”,即这里的函数都是后边直接拿来用的。在这个脚本中有两个重要的方法(目前来说)一个是get_config,单独拿出来如下

1 php 2 /** 3 * Loads the main config.php file 4 * 5 * This function lets us grab the config file even if the Config class 6 * hasn't been instantiated yet 7 * 8 * @access private 9 * @return array 10 */ 11 if ( ! function_exists('get_config')) 12 { 13 function &get_config($replace = array()) 14 { 15 static $_config; 16 17 if (isset($_config)) 18 { 19 return $_config[0]; 20 } 21 22 // Is the config file in the environment folder? 23 if ( ! defined('ENVIRONMENT') OR ! file_exists($file_path = APPPATH.'config/'.ENVIRONMENT.'/config.php')) 24 { 25 $file_path = APPPATH.'config/config.php'; 26 } 27 28 // Fetch the config file 29 if ( ! file_exists($file_path)) 30 { 31 exit('The configuration file does not exist.'); 32 } 33 34 require($file_path); 35 36 // Does the $config array exist in the file? 37 if ( ! isset($config) OR ! is_array($config)) 38 { 39 exit('Your config file does not appear to be formatted correctly.'); 40 } 41 42 // Are any values being dynamically replaced? 43 if (count($replace) > 0) 44 { 45 foreach ($replace as $key => $val) 46 { 47 if (isset($config[$key])) 48 { 49 $config[$key] = $val; 50 } 51 } 52 } 53 54 $_config[0] =& $config; 55 return $_config[0]; 56 } 57 } View Code

  注释说它加载主要的config.php文件,它使得我们能抓取到配置文件,即便配置类还未被实例化。在CI中,有专门的核心配置类CI_Config来加载配置信息,而这里的get_config方法也能获得主要配置信息,注意是主要配置信息,在application/config目录下有很多其他的配置信息文件(前面在自定义配置变量时也说过CI将配置信息分为了很多文件),其中有一个config.php文件就是get_config能获取到的,这个文件存放的就是基本信息,如果你还想获取其他的配置信息,貌似就要用配置类了。所以如果想添加节本配置信息就在这个里边。

  如果是第一次调用get_config方法,先声明静态变量$_config,如果已定义则直接返回它的索引为0的子数组。然后查看APPPATH/config/ENVIRONMENT/config.php文件是否存在(前面打印已知ENVIRONMENT常量值,未改动就是development,原始的框架中没有这个目录,所以这里加载的是application/config/config.php(只加载了这一个,其他的配置文件没有),可以打开看看config.php中定义了一个$config数组,一些基本定义如基础链接、链接后缀、编码、语言、缓存、日志、钩子等等。如果传入一个关联数组,它会将键-值(临时)加入$_config中。总之,get_config方法主要得到的是config.php中定义的数组变量。

  与get_config相关的config_item方法则是得到这个数组变量中的某一项。

  另一个比较重要的方法是load_class:

1 php 2 /** 3 * Class registry 4 * 5 * This function acts as a singleton. If the requested class does not 6 * exist it is instantiated and set to a static variable. If it has 7 * previously been instantiated the variable is returned. 8 * 9 * @access public 10 * @param string the class name being requested 11 * @param string the directory where the class should be found 12 * @param string the class name prefix 13 * @return object 14 */ 15 if ( ! function_exists('load_class')) 16 { 17 function &load_class($class, $directory = 'libraries', $prefix = 'CI_') 18 { 19 static $_classes = array(); 20 21 // Does the class exist? If so, we're done... 22 if (isset($_classes[$class])) 23 { 24 return $_classes[$class]; 25 } 26 27 $name = FALSE; 28 29 // Look for the class first in the local application/libraries folder 30 // then in the native system/libraries folder 31 foreach (array(APPPATH, BASEPATH) as $path) 32 { 33 if (file_exists($path.$directory.'/'.$class.'.php')) 34 { 35 $name = $prefix.$class; 36 37 if (class_exists($name) === FALSE) 38 { 39 require($path.$directory.'/'.$class.'.php'); 40 } 41 42 break; 43 } 44 } 45 46 // Is the request a class extension? If so we load it too 47 if (file_exists(APPPATH.$directory.'/'.config_item('subclass_prefix').$class.'.php')) 48 { 49 $name = config_item('subclass_prefix').$class; 50 51 if (class_exists($name) === FALSE) 52 { 53 require(APPPATH.$directory.'/'.config_item('subclass_prefix').$class.'.php'); 54 } 55 } 56 57 // Did we find the class? 58 if ($name === FALSE) 59 { 60 // Note: We use exit() rather then show_error() in order to avoid a 61 // self-referencing loop with the Excptions class 62 exit('Unable to locate the specified class: '.$class.'.php'); 63 } 64 65 // Keep track of what we just loaded 66 is_loaded($class); 67 68 $_classes[$class] = new $name(); 69 return $_classes[$class]; 70 } 71 } View Code

  先看它的注释:这个方法作为一个单例,如果被请求的类没有出现过,则该类会被实例化为一个static variable,如果先前被实例化过则直接返回它。它的三个参数分别是请求的类名、所在目录,类名前缀。可以看到,目录默认是libraries,在application和system中均有它,它就是存放我们自定义的类库或者CI自带的类库的地方,就是自定义工具和CI提供的工具,如日历类、加密类、Ftp类、日志类、Session会话类、Email邮件收发类、JavaScript类、ZIP压缩类等等。或许你已经注意到这里返回的是引用而非值,就像它将加载的类作为静态变量一样,这些细节地方最终提高了整个系统的访问速度。

  大致流程:先定义一个静态数组,若数组中已有该类直接返回。先后扫描APPPATH和BASEPATH(前面已知这俩常量值)文件夹下的$directory(默认值是libraries)目录下的$class.php文件是否存在,存在则加上CI的标准类前缀CI_(第三个参数的默认值),在检查类存在与否,存在则require该文件(从这里可知,class_exists()在判断类是否存在时并不需要先加载该类文件),一旦文件出现则加载它,并break跳出。注意扫描顺序,先APPPATH后BASEPATH,假如只传第一个参数类名,则优先在我们自己开发的application目录libraries中寻找,然后才去system目录的libraries下边。

  由于我们可以对CI的核心类进行扩展(继承它们),所以在扫描完APPPATH和BASEPATH的核心类(名称以CI_为前缀)目录后,还要扫描APPPATH的libraries下边是否有自定义的扩展类(默认以MY_为前缀),有的话也要加载它们,然后实例化一个对应对象(有扩展类是扩展类)存入$_classes静态数组并返回该对象。

  对Common.php有大致了解后回到CodeIgniter.php脚本。

  54-66行:加载APPPATH.'config/constants.php'脚本,constants.php如同名字一样放的是framework constants,集中定义了一些常量,所以我们在添加常量时就可以放到这里边来定义。

    

  68-78行:首先定义了一个自定义错误处理方法_exception_handler。判断php版本,非5.3关闭magic_quotes引用,这个配置在5.3版本已弃用,提高安全性。

  80-99行:这里就是将前面说过的$assign_to_config自定义配置信息数组临时加到$_config数组中,通过get_config方法实现,前面说过$assign_to_config默认是没有定义的,这里的if语句也不会运行。

  101-109行:设置自定义脚本最大执行时间为300秒(略长,跑日志的话得更长)

  111-118行:加载核心类Benchmark,设置两个标记点。Benchmark基准测试类,就是测试某个开始标记到结束标记之间占用的内存大小、执行时间等信息,测试嘛,当然它要结合CI中一个叫分析器的东西使用。

  120-132行:加载核心类Hooks,钩子,设置了一个系统开始执行的钩子(实际未执行,因为application/config/config.php关于它的配置信息默认设置为false,即不启用钩子)。它就就相当于一个触发器,在某个东西要执行前开始执行某些代码,比如控制器加载前、加载后等,一旦控制器加载就运行指定的代码。在这里,它尝试调用一个pre_system(系统执行前)的扩展,默认不执行。

  134-145行:加载核心类Config,配置类,它用来加载其他需需要的配置信息,并且它再次加载$assign_to_config数组中配置信息如果该数组定义了的话。

  147-159行:加载核心类Utf8,编码类。

  161-166行:加载核心类URI,路由。

  168-180行:加载核心类Router,路径处理类,_set_routing方法设置好访问路径。如果路径配置数组$routing(前面提到默认是注释掉的)定义了的话,将覆盖默认的路由配置。如果你输入了不存在的脚本路径,在这一步就停住,开始报404了,当然还得Router里边的方法处理。

  Router类里面,URI作为它的一个成员存在,实际处理方法在URI类中,熟悉点的都知道CI的访问方式默认是段(segment)的形式,据说更有利于搜索引擎。一个简单的访问方式是这样的localhost/ci/index.php/Controller/Function/Arguments,它们将访问的形式解析为需要的控制器,调用的方法,以及提供的参数列表,当然也可启用传统的查询字符串形式。具体方法略复杂。

  187行:加载核心类Output。

  189-200行:通过Hooks类和Output类检测有无缓存,有的话直接输出缓存页面,跳出脚本了。这也是在CI的介绍中应用程序流程图部分,当路径处理完后,若有缓存直接输出的原因。

   

  207行:加载核心类Security。

  214行:加载核心类Input。

  221行:加载核心类Lang,语言处理。

  229-235行:加载核心类Controller,它是所有控制器的基类,而get_instance全局方法也能得到它的实例,Controller的牛逼之处在于,它将前面所有通过load_calss载入的libraries(默认)目录(APPPATH和BASEPATH)中的工具库全部实例化为对象,并作为它的属性成员。所以这里的get_instance方法得到的实例也被CI称为超级对象(super object),因为通过这个对象就可以获取所有通过前面加载的对象实例。

  238-242行:加载自定义的,对上一步的核心类CI_Controller的扩展类的文件,默认就是MY_Controller,当然前提是如果你扩展了的的话。

  243-251行:通过核心类Router的实例,提取当前访问的控制器所在的目录和类名,不存在则报错,存在则加载它,这里就加载了默认的welcome控制器文件。当然如果你自己定义了控制器类文件并访问,也是在这里被include进来的(通过Router类提取子目录$RTR->fetch_directory(),若存在,提取类名$RTR->fetch_class()来找),大概在246行的if语句块,就是检查这个类文件是否存在。

  252行:设置一个基准测试结束标记,标记加载基本核心类结束(这些测试默认不会执行)。

  256-292行:安全检查。先通过Router类取得类名和要执行的方法名,if条件检查3项内容。1. 上面的243-251行是找到了控制器对应的脚本,并且加载了它,但是假如这只是一个名字匹配的空脚本呢?里边什么都没写就不行了,于是要检查类的定义是否存在(class_exists),2. 以下划线_开头的方法名不能执行,直接报错,当然这是CI自己的的规则,也就是说无论你的类定义的以_开头的方法即使是公有访问属性也不行(除了一个_remap),3. 当类中的方法根控制器核心类中的方法同名时也不行。定义方法名时有个印象就行了。进入if中就很可能会404了。

  298行:Hooks类尝试调用一个pre_controller(控制器执行前)的扩展,默认没有。

  301-309行:基准测试类设置一个起点标记,目的在于测试控制器执行的时长(默认不显示测试信息),并且实例化前面加载的控制器类,默认的就是Welcome。

  315行:Hooks尝试执行post_controller_constructor(所调用的控制器类构造完成后)的扩展,默认没有。

  317-364行:开始调用指定的控制器类的指定方法(当然这里是默认控制器Welcome的默认方法index)。看看这个流程,首先一个if判断,如果你的控制器类中有方法_remap,只调用它了,所以前面说以下划线开头的方法除了_remap,这也是CI的一个类的方法的规则,有了这个重映射方法,只调它。默认的Welcome控制器中没有_remap方法,进入else,else中还有个if,再次判断,我们调用的方法是否在这个控制器类中,如果不在的话注定要404了,只是404的调用脚本稍有不同。假如我们得application/config/routes.php文件中的routes['404_override']选项不为空(它就是我们自定义的404错误页脚本路径),将去解析它指定的目录中类名与方法名,如果类定义不存在且文件(自定义404文件)也不存在,就直接调调show_404展示CI默认的404页,只是类定义不存在的话就加载该文件,删除原对象,再new一个新的404对象(348行),当然因类定义不存在,这里理论上是要报错的;假如routes['404_override']选项为空,那么直接启用show_404方法。这个show_404是公用方法,自然是在system/core目录下的Common.php脚本里定义的。

  如果我们调用的方法在这个控制器定义中,就要运行这行了:call_user_func_array(array(&$CI, $method), array_slice($URI->rsegments, 2));,调用$CI实例的$method方法,参数就是后边的数组(URI核心类对象的成员rsegments,它被重新索引,从下标2开始是解析的所调用方法的各个参数),$CI就是我们得控制器类实例,$method是对应调用方法。至此,才真正的调用了一个控制器的方法(默认Welcome的index方法),而这还是最简单的情况>3

  它然后就是进入Welcome控制器类调用index方法加载一个默认的页面了,就是开头的欢迎页。在index加载欢迎页($this->load->view(...))又加载了核心类

  CodeIgniter.php后面剩下的几行

  364行:设置一个基准测试标记点,控制器执行结束

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn