CI加载流程小结,ci加载小结
无聊,决定水一把。
CI(CodeIgniter)是我最早接触的一个框架,到现在也只是用了其中一点零碎的方法。一直想对其流程做个小结,却总是因各种各样的“理由”挨着。看见别人图表齐上阵,没那耐心,就从代码说起吧,权当做个笔记,纪念一下。
看在线的用户手册,也知道,将CI下载下来(最新版本2.2.1),解压到机子上,比如www目录,可改个根目录名(原名CodeIgniter-2.2-stable太长),初步目录文件如下,当然这在是windows下面。
![](http://www.bkjia.com/uploads/allimg/150311/1A02L314-0.png)
访问下,如localhost/ci/index.php,就进入CI默认的Welcome页面
![](http://www.bkjia.com/uploads/allimg/150311/1A02G528-1.png)
如何一步步加载这个页面的?首先访问的是index.php脚本
![](http://www.bkjia.com/uploads/allimg/150311/1A02G596-2.gif)
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类进行的,这里只是作为一个选择性的方式,其实没必要弄
![](http://www.bkjia.com/uploads/allimg/150311/1A02H631-3.png)
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默认是没有定义的。
![](http://www.bkjia.com/uploads/allimg/150311/1A02H2S-4.png)
从131行到index.php文件末尾主要是对一些路径变量的定义。
137-141行:是为CLI(Command-Interface Line)的调用方式准备的,是直接在Mac/Linux系统上通过终端命令运行脚本,这个在CI中文官网(http://codeigniter.org.cn/user_guide/general/cli.html)也有介绍,如果定义了名为STDIN的常量,则将执行目录改为当前文件所在目录,当然前面没有出现过STDIN这个常量的定义,这里就不会执行了。
![](http://www.bkjia.com/uploads/allimg/150311/1A02J007-5.png)
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得到的是相对路径。
最后打印看看这些变(常)量的值都是啥,有的与存放目录相关:
![](http://www.bkjia.com/uploads/allimg/150311/1A02I294-6.png)
202行:加载BASEPATH.'core/CodeIgniter.php'脚本,就是system目录下的核心类文件目录下的文件,进入到CI的核心类目录下的文件了。
=====================================================================================================
![](http://www.bkjia.com/uploads/allimg/150311/1A02G596-2.gif)
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,单独拿出来如下
![](http://www.bkjia.com/uploads/allimg/150311/1A02G596-2.gif)
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:
![](http://www.bkjia.com/uploads/allimg/150311/1A02G596-2.gif)
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,集中定义了一些常量,所以我们在添加常量时就可以放到这里边来定义。
![](http://www.bkjia.com/uploads/allimg/150311/1A02J031-10.png)
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的介绍中应用程序流程图部分,当路径处理完后,若有缓存直接输出的原因。
![](http://www.bkjia.com/uploads/allimg/150311/1A02L131-11.png)
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的