1 <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
2 /**
3 * Loader Class
4 *
5 * Loader组件在CI里面也是一个很重要的组件,功能也比较明了。
6 * 如果已经阅读过Controller组件,会发现Controller组件的代码也只有十来行,但它却可以做很多事,一定程度上
7 * 要归功于Loader组件这个好助手或者好基友。
8 * 不过Loader组件的代码真的不少,主要以常用的几个方法以主线来探讨:model(),view(),library(),helper();
9 */
10 class CI_Loader {
11
12 // All these are set automatically. Don't mess with them.
13 /**
14 * Nesting level of the output buffering mechanism
15 */
16 protected $_ci_ob_level;
17 /**
18 * List of paths to load views from
19 */
20 protected $_ci_view_paths = array();
21 /**
22 * List of paths to load libraries from
23 */
24 protected $_ci_library_paths = array();
25 /**
26 * List of paths to load models from
27 */
28 protected $_ci_model_paths = array();
29 /**
30 * List of paths to load helpers from
31 */
32 protected $_ci_helper_paths = array();
33 /**
34 * List of loaded base classes
35 */
36 protected $_base_classes = array(); // Set by the controller class
37 /**
38 * List of cached variables
39 */
40 protected $_ci_cached_vars = array();
41 /**
42 * List of loaded classes
43 */
44 protected $_ci_classes = array();
45 /**
46 * List of loaded files
47 */
48 protected $_ci_loaded_files = array();
49 /**
50 * List of loaded models
51 */
52 protected $_ci_models = array();
53 /**
54 * List of loaded helpers
55 */
56 protected $_ci_helpers = array();
57 /**
58 * List of class name mappings
59 */
60 protected $_ci_varmap = array('unit_test' => 'unit',
61 'user_agent' => 'agent');
62
63 /**
64 * Constructor
65 */
66 public function __construct()
67 {
68 $this->_ci_ob_level = ob_get_level();
69 $this->_ci_library_paths = array(APPPATH, BASEPATH);
70 $this->_ci_helper_paths = array(APPPATH, BASEPATH);
71 $this->_ci_model_paths = array(APPPATH);
72 $this->_ci_view_paths = array(APPPATH.'views/' => TRUE);
73
74 log_message('debug', "Loader Class Initialized");
75 }
76
77 // --------------------------------------------------------------------
78
79 /**
80 * Initialize the Loader
81 */
82 public function initialize()
83 {
84 $this->_ci_classes = array();
85 $this->_ci_loaded_files = array();
86 $this->_ci_models = array();
87
88 //这个is_loaded方法就是在core/Common.php中定义的全局函数,在Loader组件还没有加载之前,由它来负责记录
89 //哪些核心类已经加载过,现在Loader组件要加载了,就把信息交给Loader组件,保存在Loader::$_base_classes中。
90 $this->_base_classes =& is_loaded();
91
92 //自动加载,加载项是你在config/autoload.php中设置的。
93 $this->_ci_autoloader();
94
95 return $this;
96 }
97
98 // --------------------------------------------------------------------
99
100 /**
101 * Is Loaded
102 */
103 public function is_loaded($class)
104 {
105 if (isset($this->_ci_classes[$class]))
106 {
107 return $this->_ci_classes[$class];
108 }
109
110 return FALSE;
111 }
112
113 // --------------------------------------------------------------------
114
115 /**
116 * Class Loader
117 * $library为相应的类名,$params为实例化此类的时候可能要用到的参数,$object_name为给这个类的实例自义定一个名字。
118 */
119 public function library($library = '', $params = NULL, $object_name = NULL)
120 {
121 //如果是通过数组加载多个,把它拆开再调用本方法,其实它可以递归调用多维数组,不过没有这个必要。
122 if (is_array($library))
123 {
124 foreach ($library as $class)
125 {
126 $this->library($class, $params);
127 }
128
129 return;
130 }
131
132 //接下来两个if都是关于合法性的判断。
133 if ($library == '' OR isset($this->_base_classes[$library]))
134 {
135 return FALSE;
136 }
137
138 if ( ! is_null($params) && ! is_array($params))
139 {
140 $params = NULL;
141 }
142
143 //真正把类加载进来的是下面这个方法。
144 $this->_ci_load_class($library, $params, $object_name);
145 }
146
147 // --------------------------------------------------------------------
148
149 /**
150 * Model Loader
151 */
152 public function model($model, $name = '', $db_conn = FALSE)
153 {
154 //可以以数组形式同时加载多个$model
155 if (is_array($model))
156 {
157 foreach ($model as $babe)
158 {
159 $this->model($babe);
160 }
161 return;
162 }
163
164 if ($model == '')
165 {
166 return;
167 }
168
169 $path = '';
170
171 //判断是否包含目录信息
172 if (($last_slash = strrpos($model, '/')) !== FALSE)
173 {
174 $path = substr($model, 0, $last_slash + 1);
175
176 $model = substr($model, $last_slash + 1);
177 }
178
179 //如果没有给当前model定义名字,则以$model本身作为名字。
180 if ($name == '')
181 {
182 $name = $model;
183 }
184
185 //如果已经加载过此model,直接退出本函数。
186 if (in_array($name, $this->_ci_models, TRUE))
187 {
188 return;
189 }
190
191 $CI =& get_instance();
192 //如果加载的model名字与之前加载过的类有冲突,则报错。
193 if (isset($CI->$name))
194 {
195 show_error('The model name you are loading is the name of a resource that is already being used: '.$name);
196 }
197
198 //model文件必段是全小写。
199 $model = strtolower($model);
200
201 foreach ($this->_ci_model_paths as $mod_path)
202 {
203 if ( ! file_exists($mod_path.'models/'.$path.$model.'.php'))
204 {
205 continue;
206 }
207
208 //如果要求同时连接数据库。则调用Loader::database()方法加载数据库类。
209 if ($db_conn !== FALSE AND ! class_exists('CI_DB'))
210 {
211 if ($db_conn === TRUE)
212 {
213 $db_conn = '';
214 }
215
216 $CI->load->database($db_conn, FALSE, TRUE);
217 }
218
219 //加载父类model。
220 if ( ! class_exists('CI_Model'))
221 {
222 load_class('Model', 'core');
223 }
224
225 //引入当前model
226 require_once($mod_path.'models/'.$path.$model.'.php');
227
228 //把文件名的第一个字母大写作为类名,规定的命名规范。
229 $model = ucfirst($model);
230
231 $CI->$name = new $model();
232
233 //保存在Loader::_ci_models中,以后可以用它来判断某个model是否已经加载过。
234 $this->_ci_models[] = $name;
235 return;
236 }
237
238 show_error('Unable to locate the model you have specified: '.$model);
239 }
240
241 // --------------------------------------------------------------------
242
243 /**
244 * Database Loader
245 */
246 public function database($params = '', $return = FALSE, $active_record = NULL)
247 {
248 $CI =& get_instance();
249 if (class_exists('CI_DB') AND $return == FALSE AND $active_record == NULL AND isset($CI->db) AND is_object($CI->db))
250 {
251 return FALSE;
252 }
253
254 require_once(BASEPATH.'database/DB.php');
255
256 if ($return === TRUE)
257 {
258 return DB($params, $active_record);
259 }
260 $CI->db = '';
261
262 $CI->db =& DB($params, $active_record);
263 }
264
265 // --------------------------------------------------------------------
266
267 /**
268 * Load the Utilities Class
269 */
270 public function dbutil()
271 {
272 if ( ! class_exists('CI_DB'))
273 {
274 $this->database();
275 }
276
277 $CI =& get_instance();
278
279 // for backwards compatibility, load dbforge so we can extend dbutils off it
280 // this use is deprecated and strongly discouraged
281 $CI->load->dbforge();
282
283 require_once(BASEPATH.'database/DB_utility.php');
284 require_once(BASEPATH.'database/drivers/'.$CI->db->dbdriver.'/'.$CI->db->dbdriver.'_utility.php');
285 $class = 'CI_DB_'.$CI->db->dbdriver.'_utility';
286
287 $CI->dbutil = new $class();
288 }
289
290 // --------------------------------------------------------------------
291
292 /**
293 * Load the Database Forge Class
294 */
295 public function dbforge()
296 {
297 if ( ! class_exists('CI_DB'))
298 {
299 $this->database();
300 }
301
302 $CI =& get_instance();
303
304 require_once(BASEPATH.'database/DB_forge.php');
305 require_once(BASEPATH.'database/drivers/'.$CI->db->dbdriver.'/'.$CI->db->dbdriver.'_forge.php');
306 $class = 'CI_DB_'.$CI->db->dbdriver.'_forge';
307
308 $CI->dbforge = new $class();
309 }
310
311 // --------------------------------------------------------------------
312
313 /**
314 * Load View
315 *
316 * Loader::view();方法可以和Loader::file()方法一并来阅读,实质上它们都是调用了Loader::_ci_load();方法。
317 */
318 public function view($view, $vars = array(), $return = FALSE)
319 {
320 return $this->_ci_load(array('_ci_view' => $view, '_ci_vars' => $this->_ci_object_to_array($vars), '_ci_return' => $return));
321 }
322
323 // --------------------------------------------------------------------
324
325 /**
326 * Load File
327 */
328 public function file($path, $return = FALSE)
329 {
330 return $this->_ci_load(array('_ci_path' => $path, '_ci_return' => $return));
331 }
332
333 // --------------------------------------------------------------------
334
335 /**
336 * Set Variables
337 */
338 public function vars($vars = array(), $val = '')
339 {
340 if ($val != '' AND is_string($vars))
341 {
342 $vars = array($vars => $val);
343 }
344
345 $vars = $this->_ci_object_to_array($vars);
346
347 if (is_array($vars) AND count($vars) > 0)
348 {
349 foreach ($vars as $key => $val)
350 {
351 $this->_ci_cached_vars[$key] = $val;
352 }
353 }
354 }
355
356 // --------------------------------------------------------------------
357
358 /**
359 * Get Variable
360 */
361 public function get_var($key)
362 {
363 return isset($this->_ci_cached_vars[$key]) ? $this->_ci_cached_vars[$key] : NULL;
364 }
365
366 // --------------------------------------------------------------------
367
368 /**
369 * Load Helper
370 */
371 public function helper($helpers = array())
372 {
373 //Loader::_ci_prep_filename()方法只是处理文件名,以返回正确的数组而已。
374 //默认helper的文件名是以_helper为后缀,所以参数可以不用写_helper后缀,当然写也不会出错,因为
375 //Loader::_ci_prep_filename()会帮你处理掉。
376 foreach ($this->_ci_prep_filename($helpers, '_helper') as $helper)
377 {
378 //如果已经加载过此helper,则跳过。
379 if (isset($this->_ci_helpers[$helper]))
380 {
381 continue;
382 }
383
384 //helper的扩展。并非只有类可以扩展,函数也提供了扩展。注意这里是在APPPATH下。
385 $ext_helper = APPPATH.'helpers/'.config_item('subclass_prefix').$helper.'.php';
386 //如果存在对些helper的扩展。
387 if (file_exists($ext_helper))
388 {
389 //先引入CI自带的helper,再引入我们写的扩展。
390 $base_helper = BASEPATH.'helpers/'.$helper.'.php';
391
392 if ( ! file_exists($base_helper))
393 {
394 show_error('Unable to load the requested file: helpers/'.$helper.'.php');
395 }
396
397 include_once($ext_helper);
398 include_once($base_helper);
399
400 $this->_ci_helpers[$helper] = TRUE;
401 log_message('debug', 'Helper loaded: '.$helper);
402 continue;//继续下一个helper的引入。
403 }
404
405 //如果没有扩展的话,则分别从APPPATH和BASEPATH,即应用目录和系统目录下找到相应的helper。
406 //Loader::_ci_helper_paths默认是APPPATH和BASEPATH两个目录。如果你要再添加新的目录路径,可以
407 //通过Loader::add_package_path()方法设置(model,library等同理)
408 foreach ($this->_ci_helper_paths as $path)
409 {
410 if (file_exists($path.'helpers/'.$helper.'.php'))
411 {
412 include_once($path.'helpers/'.$helper.'.php');
413
414 $this->_ci_helpers[$helper] = TRUE;
415 log_message('debug', 'Helper loaded: '.$helper);
416 break;
417 }
418 }
419
420 if ( ! isset($this->_ci_helpers[$helper]))
421 {
422 show_error('Unable to load the requested file: helpers/'.$helper.'.php');
423 }
424 }
425 }
426
427 // --------------------------------------------------------------------
428
429 /**
430 * Load Helpers
431 */
432 public function helpers($helpers = array())
433 {
434 $this->helper($helpers);
435 }
436
437 // --------------------------------------------------------------------
438
439 /**
440 * Loads a language file
441 */
442 public function language($file = array(), $lang = '')
443 {
444 $CI =& get_instance();
445
446 if ( ! is_array($file))
447 {
448 $file = array($file);
449 }
450
451 foreach ($file as $langfile)
452 {
453 $CI->lang->load($langfile, $lang);
454 }
455 }
456
457 // --------------------------------------------------------------------
458
459 /**
460 * Loads a config file
461 */
462 //这里的config方法,实质是完完全全调用Config组件的load方法而已。
463 public function config($file = '', $use_sections = FALSE, $fail_gracefully = FALSE)
464 {
465 $CI =& get_instance();
466 $CI->config->load($file, $use_sections, $fail_gracefully);
467 }
468
469 // --------------------------------------------------------------------
470
471 /**
472 * Driver
473 */
474 public function driver($library = '', $params = NULL, $object_name = NULL)
475 {
476 if ( ! class_exists('CI_Driver_Library'))
477 {
478 require BASEPATH.'libraries/Driver.php';
479 }
480
481 if ($library == '')
482 {
483 return FALSE;
484 }
485
486 if ( ! strpos($library, '/'))
487 {
488 $library = ucfirst($library).'/'.$library;
489 }
490
491 return $this->library($library, $params, $object_name);
492 }
493
494 // --------------------------------------------------------------------
495
496 /**
497 * Add Package Path
498 */
499 public function add_package_path($path, $view_cascade=TRUE)
500 {
501 $path = rtrim($path, '/').'/';
502
503 array_unshift($this->_ci_library_paths, $path);
504 array_unshift($this->_ci_model_paths, $path);
505 array_unshift($this->_ci_helper_paths, $path);
506
507 $this->_ci_view_paths = array($path.'views/' => $view_cascade) + $this->_ci_view_paths;
508
509 $config =& $this->_ci_get_component('config');
510 array_unshift($config->_config_paths, $path);
511 }
512
513 // --------------------------------------------------------------------
514
515 /**
516 * Get Package Paths
517 *
518 */
519 public function get_package_paths($include_base = FALSE)
520 {
521 return $include_base === TRUE ? $this->_ci_library_paths : $this->_ci_model_paths;
522 }
523
524 // --------------------------------------------------------------------
525
526 /**
527 * Remove Package Path
528 */
529 public function remove_package_path($path = '', $remove_config_path = TRUE)
530 {
531 $config =& $this->_ci_get_component('config');
532
533 if ($path == '')
534 {
535 $void = array_shift($this->_ci_library_paths);
536 $void = array_shift($this->_ci_model_paths);
537 $void = array_shift($this->_ci_helper_paths);
538 $void = array_shift($this->_ci_view_paths);
539 $void = array_shift($config->_config_paths);
540 }
541 else
542 {
543 $path = rtrim($path, '/').'/';
544 foreach (array('_ci_library_paths', '_ci_model_paths', '_ci_helper_paths') as $var)
545 {
546 if (($key = array_search($path, $this->{$var})) !== FALSE)
547 {
548 unset($this->{$var}[$key]);
549 }
550 }
551
552 if (isset($this->_ci_view_paths[$path.'views/']))
553 {
554 unset($this->_ci_view_paths[$path.'views/']);
555 }
556
557 if (($key = array_search($path, $config->_config_paths)) !== FALSE)
558 {
559 unset($config->_config_paths[$key]);
560 }
561 }
562
563 $this->_ci_library_paths = array_unique(array_merge($this->_ci_library_paths, array(APPPATH, BASEPATH)));
564 $this->_ci_helper_paths = array_unique(array_merge($this->_ci_helper_paths, array(APPPATH, BASEPATH)));
565 $this->_ci_model_paths = array_unique(array_merge($this->_ci_model_paths, array(APPPATH)));
566 $this->_ci_view_paths = array_merge($this->_ci_view_paths, array(APPPATH.'views/' => TRUE));
567 $config->_config_paths = array_unique(array_merge($config->_config_paths, array(APPPATH)));
568 }
569
570 // --------------------------------------------------------------------
571
572 /**
573 * Loader
574 */
575 protected function _ci_load($_ci_data)
576 {
577 //这里相当于把数组里面的元素拆开成变量。
578 foreach (array('_ci_view', '_ci_vars', '_ci_path', '_ci_return') as $_ci_val)
579 {
580 $$_ci_val = ( ! isset($_ci_data[$_ci_val])) ? FALSE : $_ci_data[$_ci_val];
581 }
582
583 $file_exists = FALSE;
584
585 //当Loader::_ci_load()方法是通过Loader::file()调用的时候,则会有$_ci_path的值,如果是
586 //如果Loader::view()调用的话,则有$_ci_view的值。
587 //如果$_ci_path不为空,则说明当前要加载普通文件。
588 if ($_ci_path != '')
589 {
590 //普通文件。这里只是获得文件名,以便找不到报错时候只报文件名而已。
591 $_ci_x = explode('/', $_ci_path);
592 $_ci_file = end($_ci_x);
593 }
594 else
595 {
596 //视图文件。
597 //下面两行操作也是为了让外部可以通过xxx.php或者直接xxx的方式进行传参而已。
598 $_ci_ext = pathinfo($_ci_view, PATHINFO_EXTENSION);
599 $_ci_file = ($_ci_ext == '') ? $_ci_view.'.php' : $_ci_view;
600
601 foreach ($this->_ci_view_paths as $view_file => $cascade)
602 {
603 //从Loader::$_ci_view_paths中遍历视图文件,如果找到则退出。
604 //(默认仅有APPPATH/view/下,当然也可以通过Loader::add_package()方法设置)
605 if (file_exists($view_file.$_ci_file))
606 {
607 $_ci_path = $view_file.$_ci_file;
608 $file_exists = TRUE;
609 break;
610 }
611
612 //如果没有找到,会根据这个$cascade判断允不允许继续往下一个路径寻找视图文件。
613 if ( ! $cascade)
614 {
615 break;
616 }
617 }
618 }
619
620 //如果找不到文件(普通或视图都一样),则报错。
621 if ( ! $file_exists && ! file_exists($_ci_path))
622 {
623 show_error('Unable to load the requested file: '.$_ci_file);
624 }
625
626 //下面这个也很关键,其实视图文件里面的代码都是在属于Loader组件的,什么意思?
627 //你可以随便写一个视图文件,然后在里面写上var_dump($this);可以发现,这个$this,是指Loader。
628 //为什么会这样子呢?再往下面十几行代码的地方就说明了这一点。
629 //这里是把CI所有的属性都开放给Loader组件用,这样在视图文件里面就可以通过$this->xxx的方式调用控制器
630 //所有的东西。
631
632 $_ci_CI =& get_instance();
633 foreach (get_object_vars($_ci_CI) as $_ci_key => $_ci_var)
634 {
635 if ( ! isset($this->$_ci_key))
636 {
637 $this->$_ci_key =& $_ci_CI->$_ci_key;
638 }
639 }
640
641 //在这里把在控制器里面通过$this->load->view("xxx",$data);中的$data解开,这就是为什么可以在视图文件
642 //中可以用$data里面的变量的原因。其实还可以通过Loader::vars()方法,设置这些变量,它们会首先保存在
643 //Loader::$_ci_cached_vars中
644 if (is_array($_ci_vars))
645 {
646 $this->_ci_cached_vars = array_merge($this->_ci_cached_vars, $_ci_vars);
647 }
648 extract($this->_ci_cached_vars);
649
650 //我们在控制器中调用$this->load->view()方法,实质视图并没有马上输出来,而是先将它放到缓冲区。
651 ob_start();
652
653 //就是这个地方,下面if中有一句eval(xxxx)以及else中有include;而里面的xxxx正是我们要加载的视图文件,
654 //所以这就是为什么在视图文件里,var_dump($this),会告诉你当前这个$this是Loader组件,因为视图的代码都是相当于
655 //嵌入这个地方。
656 if ((bool) @ini_get('short_open_tag') === FALSE AND config_item('rewrite_short_tags') == TRUE)
657 {
658 echo eval('?>'.preg_replace("/;*\s*\?>/", "; ?>", str_replace('<?=', '<?php echo ', file_get_contents($_ci_path))));//'
659 }
660 else
661 {
662 include($_ci_path);
663 }
664
665 //经过上面的代码,我们的视图文件的内容已经放到了缓冲区了。
666
667 log_message('debug', 'File loaded: '.$_ci_path);
668
669 //一般情况下,$_ci_return都为FLASE,即不要求通过$this->load->view()返回输出内容,而是直接放到缓冲区静候处理;
670 //当然你也可以先拿出数据,在控制器里面处理一下,再输出,例如在控制器中
671 //$output=$this->load->view("x",$data,TRUE);,当为TRUE的时候,下面的代码就起作用了。
672 if ($_ci_return === TRUE)
673 {
674 $buffer = ob_get_contents();
675 @ob_end_clean();
676 return $buffer;
677 }
678
679 //下面这个很关键,因为有可能当前这个视图文件是被另一个视图文件通过$this->view()方法引入,即视图文件嵌入视图文件
680 //从而导致多了一层缓冲。
681 //为了保证缓冲内容最后交给Output处理时,缓冲级别只比Loader组件加载时多1(这个1就是最父层的视图文件引起的)
682 //这里必须先flush掉当前层视图引起的这次缓冲,以保证Output正常工作。
683 if (ob_get_level() > $this->_ci_ob_level + 1)
684 {
685 ob_end_flush();
686 }
687 else
688 {
689 //如果不是多1,则说明当前引入的视图文件就是直接在控制器里面引入的那个,而不是由某个视图文件再引入的。
690
691 //把缓冲区的内容交给Output组件并清空关闭缓冲区。
692 $_ci_CI->output->append_output(ob_get_contents());
693 @ob_end_clean();
694 }
695 }
696
697 // --------------------------------------------------------------------
698
699 /**
700 * Load class
701 */
702 protected function _ci_load_class($class, $params = NULL, $object_name = NULL)
703 {
704 //去掉后缀.php,是为了方便外部可以通过xxx.php也可以通过xxx.php来传入类名。同时去掉两端的/。
705 $class = str_replace('.php', '', trim($class, '/'));
706
707 //因为CI允许通过"dir1/dir2/classname"的格式来组织和加载类,所以还要判断类名中是否包括这些目录信息。
708 $subdir = '';
709 if (($last_slash = strrpos($class, '/')) !== FALSE)
710 {
711 //目录部分
712 $subdir = substr($class, 0, $last_slash + 1);
713
714 //类名部分
715 $class = substr($class, $last_slash + 1);
716 }
717
718 //CI允许类文件以大写字母开头或者全小写,下面的遍历,就是在遍历这两种情况。
719 foreach (array(ucfirst($class), strtolower($class)) as $class)
720 {
721 $subclass = APPPATH.'libraries/'.$subdir.config_item('subclass_prefix').$class.'.php';
722
723 //是否有我们开发人员自己写的扩展当前类的扩展?如果有的话,把它加载进来。
724 if (file_exists($subclass))
725 {
726 //先加载父类。
727 $baseclass = BASEPATH.'libraries/'.ucfirst($class).'.php';
728
729 if ( ! file_exists($baseclass))
730 {
731 log_message('error', "Unable to load the requested class: ".$class);
732 show_error("Unable to load the requested class: ".$class);
733 }
734
735 if (in_array($subclass, $this->_ci_loaded_files))
736 {
737
738 if ( ! is_null($object_name))
739 {
740 $CI =& get_instance();
741 //我们加载的类最终都是加载给超级控制器的,如果超级控制器已经有的话,那么我们没必要加载。
742 //如果没有,则实例它并加载给控制器。,
743 if ( ! isset($CI->$object_name))
744 {
745 return $this->_ci_init_class($class, config_item('subclass_prefix'), $params, $object_name);
746 }
747 }
748
749 $is_duplicate = TRUE;
750 log_message('debug', $class." class already loaded. Second attempt ignored.");
751 return;
752 }
753
754 //加载类。
755 include_once($baseclass);
756 include_once($subclass);
757 //把已加载的类记录到Loader::_ci_loaded_files中。
758 $this->_ci_loaded_files[] = $subclass;
759
760 //调用Loader::_ci_init_class()方法进而实例化。
761 return $this->_ci_init_class($class, config_item('subclass_prefix'), $params, $object_name);
762 }
763
764 //如果是没有写扩展。方法和上面大致相同,最后都是通过调用Loader::_ci_init_class()方法进而实例化。
765
766 $is_duplicate = FALSE;
767 foreach ($this->_ci_library_paths as $path)
768 {
769 $filepath = $path.'libraries/'.$subdir.$class.'.php';
770 if ( ! file_exists($filepath))
771 {
772 continue;
773 }
774
775 if (in_array($filepath, $this->_ci_loaded_files))
776 {
777 if ( ! is_null($object_name))
778 {
779 $CI =& get_instance();
780 if ( ! isset($CI->$object_name))
781 {
782 return $this->_ci_init_class($class, '', $params, $object_name);
783 }
784 }
785
786 $is_duplicate = TRUE;
787 log_message('debug', $class." class already loaded. Second attempt ignored.");
788 return;
789 }
790
791 include_once($filepath);
792 $this->_ci_loaded_files[] = $filepath;
793 return $this->_ci_init_class($class, '', $params, $object_name);
794 }
795
796 } // END FOREACH
797
798 //其实正常的话,上面如果找到此类就找到,没找到就没有了。不过CI在会这里做最后的尝试。会不会是放到了一个同名的
799 //子目录下。
800 if ($subdir == '')
801 {
802 $path = strtolower($class).'/'.$class;
803 return $this->_ci_load_class($path, $params);
804 }
805
806
807 //没有找到就报错咯。
808 if ($is_duplicate == FALSE)
809 {
810 log_message('error', "Unable to load the requested class: ".$class);
811 show_error("Unable to load the requested class: ".$class);
812 }
813 }
814
815 // --------------------------------------------------------------------
816
817 //此方法是用于实例化已经把类文件include进来的类。
818 protected function _ci_init_class($class, $prefix = '', $config = FALSE, $object_name = NULL)
819 {
820 // Is there an associated config file for this class? Note: these should always be lowercase
821 if ($config === NULL)
822 {
823 // Fetch the config paths containing any package paths
824 $config_component = $this->_ci_get_component('config');
825
826 if (is_array($config_component->_config_paths))
827 {
828 // Break on the first found file, thus package files
829 // are not overridden by default paths
830 foreach ($config_component->_config_paths as $path)
831 {
832 // We test for both uppercase and lowercase, for servers that
833 // are case-sensitive with regard to file names. Check for environment
834 // first, global next
835 if (defined('ENVIRONMENT') AND file_exists($path .'config/'.ENVIRONMENT.'/'.strtolower($class).'.php'))
836 {
837 include($path .'config/'.ENVIRONMENT.'/'.strtolower($class).'.php');
838 break;
839 }
840 elseif (defined('ENVIRONMENT') AND file_exists($path .'config/'.ENVIRONMENT.'/'.ucfirst(strtolower($class)).'.php'))
841 {
842 include($path .'config/'.ENVIRONMENT.'/'.ucfirst(strtolower($class)).'.php');
843 break;
844 }
845 elseif (file_exists($path .'config/'.strtolower($class).'.php'))
846 {
847 include($path .'config/'.strtolower($class).'.php');
848 break;
849 }
850 elseif (file_exists($path .'config/'.ucfirst(strtolower($class)).'.php'))
851 {
852 include($path .'config/'.ucfirst(strtolower($class)).'.php');
853 break;
854 }
855 }
856 }
857 }
858
859 if ($prefix == '')
860 {
861 if (class_exists('CI_'.$class))
862 {
863 $name = 'CI_'.$class;
864 }
865 elseif (class_exists(config_item('subclass_prefix').$class))
866 {
867 $name = config_item('subclass_prefix').$class;
868 }
869 else
870 {
871 $name = $class;
872 }
873 }
874 else
875 {
876 $name = $prefix.$class;
877 }
878
879 // Is the class name valid?
880 if ( ! class_exists($name))
881 {
882 log_message('error', "Non-existent class: ".$name);
883 show_error("Non-existent class: ".$class);
884 }
885
886 // Set the variable name we will assign the class to
887 // Was a custom class name supplied? If so we'll use it
888 $class = strtolower($class);
889
890 if (is_null($object_name))
891 {
892 $classvar = ( ! isset($this->_ci_varmap[$class])) ? $class : $this->_ci_varmap[$class];
893 }
894 else
895 {
896 $classvar = $object_name;
897 }
898
899 // Save the class name and object name
900 $this->_ci_classes[$class] = $classvar;
901
902 // Instantiate the class
903 $CI =& get_instance();
904 if ($config !== NULL)
905 {
906 $CI->$classvar = new $name($config);
907 }
908 else
909 {
910 $CI->$classvar = new $name;
911 }
912 }
913
914 // --------------------------------------------------------------------
915
916 /**
917 * Autoloader
918 *
919 * The config/autoload.php file contains an array that permits sub-systems,
920 * libraries, and helpers to be loaded automatically.
921 *
922 */
923 private function _ci_autoloader()
924 {
925 if (defined('ENVIRONMENT') AND file_exists(APPPATH.'config/'.ENVIRONMENT.'/autoload.php'))
926 {
927 include(APPPATH.'config/'.ENVIRONMENT.'/autoload.php');
928 }
929 else
930 {
931 include(APPPATH.'config/autoload.php');
932 }
933
934 if ( ! isset($autoload))
935 {
936 return FALSE;
937 }
938
939 // Autoload packages
940 if (isset($autoload['packages']))
941 {
942 foreach ($autoload['packages'] as $package_path)
943 {
944 $this->add_package_path($package_path);
945 }
946 }
947
948 // Load any custom config file
949 if (count($autoload['config']) > 0)
950 {
951 $CI =& get_instance();
952 foreach ($autoload['config'] as $key => $val)
953 {
954 $CI->config->load($val);
955 }
956 }
957
958 // Autoload helpers and languages
959 foreach (array('helper', 'language') as $type)
960 {
961 if (isset($autoload[$type]) AND count($autoload[$type]) > 0)
962 {
963 $this->$type($autoload[$type]);
964 }
965 }
966
967 // A little tweak to remain backward compatible
968 // The $autoload['core'] item was deprecated
969 if ( ! isset($autoload['libraries']) AND isset($autoload['core']))
970 {
971 $autoload['libraries'] = $autoload['core'];
972 }
973
974 // Load libraries
975 if (isset($autoload['libraries']) AND count($autoload['libraries']) > 0)
976 {
977 // Load the database driver.
978 if (in_array('database', $autoload['libraries']))
979 {
980 $this->database();
981 $autoload['libraries'] = array_diff($autoload['libraries'], array('database'));
982 }
983
984 // Load all other libraries
985 foreach ($autoload['libraries'] as $item)
986 {
987 $this->library($item);
988 }
989 }
990
991 // Autoload models
992 if (isset($autoload['model']))
993 {
994 $this->model($autoload['model']);
995 }
996 }
997
998 // --------------------------------------------------------------------
999
1000 /**
1001 * Object to Array
1002 *
1003 * Takes an object as input and converts the class variables to array key/vals
1004 *
1005 */
1006 protected function _ci_object_to_array($object)
1007 {
1008 return (is_object($object)) ? get_object_vars($object) : $object;
1009 }
1010
1011 // --------------------------------------------------------------------
1012
1013 /**
1014 * Get a reference to a specific library or model
1015 *
1016 */
1017 protected function &_ci_get_component($component)
1018 {
1019 $CI =& get_instance();
1020 return $CI->$component;
1021 }
1022
1023 // --------------------------------------------------------------------
1024
1025 /**
1026 * Prep filename
1027 *
1028 * This function preps the name of various items to make loading them more reliable.
1029 *
1030 */
1031 protected function _ci_prep_filename($filename, $extension)
1032 {
1033 if ( ! is_array($filename))
1034 {
1035 return array(strtolower(str_replace('.php', '', str_replace($extension, '', $filename)).$extension));
1036 }
1037 else
1038 {
1039 foreach ($filename as $key => $val)
1040 {
1041 $filename[$key] = strtolower(str_replace('.php', '', str_replace($extension, '', $val)).$extension);
1042 }
1043
1044 return $filename;
1045 }
1046 }
1047 }