欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  后端开发

CI加载流程小结

程序员文章站 2022-04-13 12:55:16
...
  无聊,决定水一把。

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

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

   CI加载流程小结

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

  CI加载流程小结

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

CI加载流程小结CI加载流程小结

  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类进行的,这里只是作为一个选择性的方式,其实没必要弄

   CI加载流程小结

  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默认是没有定义的。

   CI加载流程小结

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

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

   CI加载流程小结

  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得到的是相对路径。

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

  CI加载流程小结

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

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

CI加载流程小结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,单独拿出来如下

CI加载流程小结CI加载流程小结

 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:

CI加载流程小结CI加载流程小结

 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,集中定义了一些常量,所以我们在添加常量时就可以放到这里边来定义。

   CI加载流程小结

  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的介绍中应用程序流程图部分,当路径处理完后,若有缓存直接输出的原因。

   CI加载流程小结

  207行:加载核心类Security。

  214行:加载核心类Input。

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

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

  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

CI加载流程小结

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。

相关文章

相关视频


网友评论

文明上网理性发言,请遵守 新闻评论服务协议

我要评论
  • CI加载流程小结
  • 专题推荐

    作者信息
    CI加载流程小结

    认证0级讲师

    推荐视频教程
  • CI加载流程小结javascript初级视频教程
  • CI加载流程小结jquery 基础视频教程
  • 视频教程分类