zoukankan      html  css  js  c++  java
  • 十三)CodeIgniter源码分析之Loader.php

       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 }
  • 相关阅读:
    【Java】【高精度】【组合数】【递推】poj1737 Connected Graph
    【递推】【推导】【乘法逆元】UVA
    【Java】【滚动数组】【动态规划】UVA
    【Java】【高精度】【递推】UVA
    【贪心】【multiset】Tinkoff Challenge
    【递推】【组合数】【容斥原理】UVA
    【递推】【组合计数】UVA
    【组合计数】UVA
    【预处理】【分类讨论】Playrix Codescapes Cup (Codeforces Round #413, rated, Div. 1 + Div. 2) C. Fountains
    【DFS】【贪心】Codeforces Round #411 (Div. 1) C. Ice cream coloring
  • 原文地址:https://www.cnblogs.com/qxbj/p/4415260.html
Copyright © 2011-2022 走看看