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 }
时间: 2024-10-05 16:57:34