1. 云栖社区>
  2. PHP教程>
  3. 正文

CI框架装载器Loader.php源码分析

作者:用户 来源:互联网 时间:2017-12-01 20:00:38

框架源码分析装载

CI框架装载器Loader.php源码分析 - 摘要: 本文讲的是CI框架装载器Loader.php源码分析,顾名思义,装载器就是加载元素的,使用CI时,经常加载的有:$this->load->library()$this->load->view()$this->load->model()$this->lo

顾名思义,装载器就是加载元素的,使用CI时,经常加载的有:

$this->load->library()

$this->load->view()

$this->load->model()

$this->load->database()

$this->load->helper()

$this->load->config()

$this->load->add_package_path()
/** * Loader Class * * 用户加载views和files,常见的函数有model(),view(),library(),helper() *  * Controller的好助手,$this->load =& load_class('Loader', 'core');,加载了loader,Controller就无比强大了 */class CI_Loader { protected $_ci_ob_level; protected $_ci_view_paths  = array(); protected $_ci_library_paths = array(); protected $_ci_model_paths  = array(); protected $_ci_helper_paths  = array(); protected $_base_classes  = array(); // Set by the controller class protected $_ci_cached_vars  = array(); protected $_ci_classes   = array(); protected $_ci_loaded_files  = array();  protected $_ci_models   = array(); protected $_ci_helpers   = array(); protected $_ci_varmap   = array('unit_test' => 'unit',   'user_agent' => 'agent'); public function __construct() {       //获取缓冲嵌套级别  $this->_ci_ob_level  = ob_get_level();  //library路径$this->_ci_library_paths = array(APPPATH, BASEPATH);//helper路径  $this->_ci_helper_paths = array(APPPATH, BASEPATH);//model路径  $this->_ci_model_paths = array(APPPATH);//view路径  $this->_ci_view_paths = array(APPPATH.'views/' => TRUE);  log_message('debug', "Loader Class Initialized"); } // -------------------------------------------------------------------- /**  * 初始化Loader  *  */ public function initialize() {  $this->_ci_classes = array();  $this->_ci_loaded_files = array();  $this->_ci_models = array();//将is_loaded(common中记录加载核心类函数)加载的核心类交给_base_classes  $this->_base_classes =& is_loaded();//加载autoload.php配置中文件  $this->_ci_autoloader();  return $this; } // -------------------------------------------------------------------- /**  * 检测类是否加载  */ public function is_loaded($class) {  if (isset($this->_ci_classes[$class]))  {   return $this->_ci_classes[$class];  }  return FALSE; } // -------------------------------------------------------------------- /**  * 加载Class  */ public function library($library = '', $params = NULL, $object_name = NULL) {  if (is_array($library))  {   foreach ($library as $class)   {    $this->library($class, $params);   }   return;  }//如果$library为空或者已经加载。。。  if ($library == '' OR isset($this->_base_classes[$library]))  {   return FALSE;  }  if ( ! is_null($params) && ! is_array($params))  {   $params = NULL;  }  $this->_ci_load_class($library, $params, $object_name); } // -------------------------------------------------------------------- /**  * 加载和实例化model  */ public function model($model, $name = '', $db_conn = FALSE) {//CI支持数组加载多个model  if (is_array($model))  {   foreach ($model as $babe)   {    $this->model($babe);   }   return;  }  if ($model == '')  {   return;  }  $path = '';  // 是否存在子目录  if (($last_slash = strrpos($model, '/')) !== FALSE)  {   // The path is in front of the last slash   $path = substr($model, 0, $last_slash + 1);   // And the model name behind it   $model = substr($model, $last_slash + 1);  }  if ($name == '')  {   $name = $model;  }  if (in_array($name, $this->_ci_models, TRUE))  {   return;  }  $CI =& get_instance();  if (isset($CI->$name))  {   show_error('The model name you are loading is the name of a resource that is already being used: '.$name);  }  $model = strtolower($model); //model文件名全小写  foreach ($this->_ci_model_paths as $mod_path)  {   if ( ! file_exists($mod_path.'models/'.$path.$model.'.php'))   {    continue;   }   if ($db_conn !== FALSE AND ! class_exists('CI_DB'))   {    if ($db_conn === TRUE)    {     $db_conn = '';    }    $CI->load->database($db_conn, FALSE, TRUE);   }   if ( ! class_exists('CI_Model'))   {    load_class('Model', 'core');   }   require_once($mod_path.'models/'.$path.$model.'.php');   $model = ucfirst($model);   $CI->$name = new $model();//保存在Loader::_ci_models中,以后可以用它来判断某个model是否已经加载过。   $this->_ci_models[] = $name;   return;  }  // couldn't find the model  show_error('Unable to locate the model you have specified: '.$model); } // -------------------------------------------------------------------- /**  * 数据库Loader  */ public function database($params = '', $return = FALSE, $active_record = NULL) {  // Grab the super object  $CI =& get_instance();  // 是否需要加载db  if (class_exists('CI_DB') AND $return == FALSE AND $active_record == NULL AND isset($CI->db) AND is_object($CI->db))  {   return FALSE;  }  require_once(BASEPATH.'database/DB.php');  if ($return === TRUE)  {   return DB($params, $active_record);  }  // Initialize the db variable.  Needed to prevent  // reference errors with some configurations  $CI->db = '';  // Load the DB class  $CI->db =& DB($params, $active_record); } // -------------------------------------------------------------------- /**  * 加载数据库工具类  */ public function dbutil() {  if ( ! class_exists('CI_DB'))  {   $this->database();  }  $CI =& get_instance();  // for backwards compatibility, load dbforge so we can extend dbutils off it  // this use is deprecated and strongly discouraged  $CI->load->dbforge();  require_once(BASEPATH.'database/DB_utility.php');  require_once(BASEPATH.'database/drivers/'.$CI->db->dbdriver.'/'.$CI->db->dbdriver.'_utility.php');  $class = 'CI_DB_'.$CI->db->dbdriver.'_utility';  $CI->dbutil = new $class(); } // -------------------------------------------------------------------- /**  * Load the Database Forge Class  *  * @return string  */ public function dbforge() {  if ( ! class_exists('CI_DB'))  {   $this->database();  }  $CI =& get_instance();  require_once(BASEPATH.'database/DB_forge.php');  require_once(BASEPATH.'database/drivers/'.$CI->db->dbdriver.'/'.$CI->db->dbdriver.'_forge.php');  $class = 'CI_DB_'.$CI->db->dbdriver.'_forge';  $CI->dbforge = new $class(); } // -------------------------------------------------------------------- /**  * 加载视图文件  */ public function view($view, $vars = array(), $return = FALSE) {  return $this->_ci_load(array('_ci_view' => $view, '_ci_vars' => $this->_ci_object_to_array($vars), '_ci_return' => $return)); } // -------------------------------------------------------------------- /**  * 加载普通文件  */ public function file($path, $return = FALSE) {  return $this->_ci_load(array('_ci_path' => $path, '_ci_return' => $return)); } // -------------------------------------------------------------------- /**  * 设置变量  *  * Once variables are set they become available within  * the controller class and its "view" files.  *  */ public function vars($vars = array(), $val = '') {  if ($val != '' AND is_string($vars))  {   $vars = array($vars => $val);  }  $vars = $this->_ci_object_to_array($vars);  if (is_array($vars) AND count($vars) > 0)  {   foreach ($vars as $key => $val)   {    $this->_ci_cached_vars[$key] = $val;   }  } } // -------------------------------------------------------------------- /**  * 检查并获取变量  */ public function get_var($key) {  return isset($this->_ci_cached_vars[$key]) ? $this->_ci_cached_vars[$key] : NULL; } // -------------------------------------------------------------------- /**  * 加载helper  */ public function helper($helpers = array()) {  foreach ($this->_ci_prep_filename($helpers, '_helper') as $helper)  {   if (isset($this->_ci_helpers[$helper]))   {    continue;   }   $ext_helper = APPPATH.'helpers/'.config_item('subclass_prefix').$helper.'.php';   // 如果是扩展helper的话   if (file_exists($ext_helper))   {    $base_helper = BASEPATH.'helpers/'.$helper.'.php';    if ( ! file_exists($base_helper))    {     show_error('Unable to load the requested file: helpers/'.$helper.'.php');    }    include_once($ext_helper);    include_once($base_helper);    $this->_ci_helpers[$helper] = TRUE;    log_message('debug', 'Helper loaded: '.$helper);    continue;   }   // 如果不是扩展helper,helper路径中加载helper   foreach ($this->_ci_helper_paths as $path)   {    if (file_exists($path.'helpers/'.$helper.'.php'))    {     include_once($path.'helpers/'.$helper.'.php');     $this->_ci_helpers[$helper] = TRUE;     log_message('debug', 'Helper loaded: '.$helper);     break;    }   }   // 如果该helper还没加载成功的话,说明加载helper失败   if ( ! isset($this->_ci_helpers[$helper]))   {    show_error('Unable to load the requested file: helpers/'.$helper.'.php');   }  } } // -------------------------------------------------------------------- /**  * 可以看到helpers调用也是上面的helper,只是helpers的别名而已  */ public function helpers($helpers = array()) {  $this->helper($helpers); } // -------------------------------------------------------------------- /**  * 加载language文件  */ public function language($file = array(), $lang = '') {  $CI =& get_instance();  if ( ! is_array($file))  {   $file = array($file);  }  foreach ($file as $langfile)  {   $CI->lang->load($langfile, $lang);  } } // -------------------------------------------------------------------- /**  * 加载配置文件  */ public function config($file = '', $use_sections = FALSE, $fail_gracefully = FALSE) {  $CI =& get_instance();  $CI->config->load($file, $use_sections, $fail_gracefully); } // -------------------------------------------------------------------- /**  * Driver  *  * 加载 driver library  */ public function driver($library = '', $params = NULL, $object_name = NULL) {  if ( ! class_exists('CI_Driver_Library'))  {   // we aren't instantiating an object here, that'll be done by the Library itself   require BASEPATH.'libraries/Driver.php';  }  if ($library == '')  {   return FALSE;  }  // We can save the loader some time since Drivers will *always* be in a subfolder,  // and typically identically named to the library  if ( ! strpos($library, '/'))  {   $library = ucfirst($library).'/'.$library;  }  return $this->library($library, $params, $object_name); } // -------------------------------------------------------------------- /**  * 添加 Package 路径  *  * 把package路径添加到库,模型,助手,配置路径  */ public function add_package_path($path, $view_cascade=TRUE) {  $path = rtrim($path, '/').'/';  array_unshift($this->_ci_library_paths, $path);  array_unshift($this->_ci_model_paths, $path);  array_unshift($this->_ci_helper_paths, $path);  $this->_ci_view_paths = array($path.'views/' => $view_cascade) + $this->_ci_view_paths;  $config =& $this->_ci_get_component('config');  array_unshift($config->_config_paths, $path); } // -------------------------------------------------------------------- /**  * 获取Package Paths,默认不包含BASEPATH  */ public function get_package_paths($include_base = FALSE) {  return $include_base === TRUE ? $this->_ci_library_paths : $this->_ci_model_paths; } // -------------------------------------------------------------------- /**  * 剔除Package Path  *  * Remove a path from the library, model, and helper path arrays if it exists  * If no path is provided, the most recently added path is removed.  *  */ public function remove_package_path($path = '', $remove_config_path = TRUE) {  $config =& $this->_ci_get_component('config');  if ($path == '')  {   $void = array_shift($this->_ci_library_paths);   $void = array_shift($this->_ci_model_paths);   $void = array_shift($this->_ci_helper_paths);   $void = array_shift($this->_ci_view_paths);   $void = array_shift($config->_config_paths);  }  else  {   $path = rtrim($path, '/').'/';   foreach (array('_ci_library_paths', '_ci_model_paths', '_ci_helper_paths') as $var)   {    if (($key = array_search($path, $this->{$var})) !== FALSE)    {     unset($this->{$var}[$key]);    }   }   if (isset($this->_ci_view_paths[$path.'views/']))   {    unset($this->_ci_view_paths[$path.'views/']);   }   if (($key = array_search($path, $config->_config_paths)) !== FALSE)   {    unset($config->_config_paths[$key]);   }  }  // 保证应用默认的路径依然存在  $this->_ci_library_paths = array_unique(array_merge($this->_ci_library_paths, array(APPPATH, BASEPATH)));  $this->_ci_helper_paths = array_unique(array_merge($this->_ci_helper_paths, array(APPPATH, BASEPATH)));  $this->_ci_model_paths = array_unique(array_merge($this->_ci_model_paths, array(APPPATH)));  $this->_ci_view_paths = array_merge($this->_ci_view_paths, array(APPPATH.'views/' => TRUE));  $config->_config_paths = array_unique(array_merge($config->_config_paths, array(APPPATH))); } // -------------------------------------------------------------------- /**  * Loader  *  * This function is used to load views and files.  * Variables are prefixed with _ci_ to avoid symbol collision with  * variables made available to view files  *  * @param array  * @return void  */ protected function _ci_load($_ci_data) {  // Set the default data variables  foreach (array('_ci_view', '_ci_vars', '_ci_path', '_ci_return') as $_ci_val)  {   $$_ci_val = ( ! isset($_ci_data[$_ci_val])) ? FALSE : $_ci_data[$_ci_val];  }  $file_exists = FALSE;//如果$_ci_path不为空,则说明当前要加载普通文件。Loader::file才会有path  if ($_ci_path != '')  {   $_ci_x = explode('/', $_ci_path);   $_ci_file = end($_ci_x);  }  else  {   $_ci_ext = pathinfo($_ci_view, PATHINFO_EXTENSION);   $_ci_file = ($_ci_ext == '') ? $_ci_view.'.php' : $_ci_view;   foreach ($this->_ci_view_paths as $view_file => $cascade)   {    if (file_exists($view_file.$_ci_file))    {     $_ci_path = $view_file.$_ci_file;     $file_exists = TRUE;     break;    }    if ( ! $cascade)    {     break;    }   }  }//view文件不存在则会报错  if ( ! $file_exists && ! file_exists($_ci_path))  {   show_error('Unable to load the requested file: '.$_ci_file);  }  // 把CI的所有属性都传递给loader,view中$this指的是loader  $_ci_CI =& get_instance();  foreach (get_object_vars($_ci_CI) as $_ci_key => $_ci_var)  {   if ( ! isset($this->$_ci_key))   {    $this->$_ci_key =& $_ci_CI->$_ci_key;   }  }  /*   * Extract and cache variables   *   * You can either set variables using the dedicated $this->load_vars()   * function or via the second parameter of this function. We'll merge   * the two types and cache them so that views that are embedded within   * other views can have access to these variables.   */  if (is_array($_ci_vars))  {   $this->_ci_cached_vars = array_merge($this->_ci_cached_vars, $_ci_vars);  }  extract($this->_ci_cached_vars);  /*   * 将视图内容放到缓存区   *   */  ob_start();  // 支持短标签  if ((bool) @ini_get('short_open_tag') === FALSE AND config_item('rewrite_short_tags') == TRUE)  {   echo eval('?>'.preg_replace("/;*/s*/?>/", "; ?>", str_replace('<?=', '<?php echo ', file_get_contents($_ci_path))));  }  else  {   include($_ci_path); // include() vs include_once() allows for multiple views with the same name  }  log_message('debug', 'File loaded: '.$_ci_path);  // 是否直接返回view数据  if ($_ci_return === TRUE)  {   $buffer = ob_get_contents();   @ob_end_clean();   return $buffer;  }  //当前这个视图文件是被另一个视图文件通过$this->view()方法引入,即视图文件嵌入视图文件  if (ob_get_level() > $this->_ci_ob_level + 1)  {   ob_end_flush();  }  else  {       ////把缓冲区的内容交给Output组件并清空关闭缓冲区。   $_ci_CI->output->append_output(ob_get_contents());   @ob_end_clean();  } } // -------------------------------------------------------------------- /**  * 加载类  */ protected function _ci_load_class($class, $params = NULL, $object_name = NULL) {  // 去掉.php和两端的/获取的$class就是类名或目录名+类名  $class = str_replace('.php', '', trim($class, '/'));  // CI允许dir/filename方式  $subdir = '';  if (($last_slash = strrpos($class, '/')) !== FALSE)  {   // 目录   $subdir = substr($class, 0, $last_slash + 1);   // 文件名   $class = substr($class, $last_slash + 1);  }  // 允许加载的类名首字母大写或全小写  foreach (array(ucfirst($class), strtolower($class)) as $class)  {   $subclass = APPPATH.'libraries/'.$subdir.config_item('subclass_prefix').$class.'.php';   // 是否是扩展类   if (file_exists($subclass))   {    $baseclass = BASEPATH.'libraries/'.ucfirst($class).'.php';    if ( ! file_exists($baseclass))    {     log_message('error', "Unable to load the requested class: ".$class);     show_error("Unable to load the requested class: ".$class);    }    // Safety:  Was the class already loaded by a previous call?    if (in_array($subclass, $this->_ci_loaded_files))    {     // Before we deem this to be a duplicate request, let's see     // if a custom object name is being supplied.  If so, we'll     // return a new instance of the object     if ( ! is_null($object_name))     {      $CI =& get_instance();      if ( ! isset($CI->$object_name))      {       return $this->_ci_init_class($class, config_item('subclass_prefix'), $params, $object_name);      }     }     $is_duplicate = TRUE;     log_message('debug', $class." class already loaded. Second attempt ignored.");     return;    }    include_once($baseclass);    include_once($subclass);    $this->_ci_loaded_files[] = $subclass;//实例化类    return $this->_ci_init_class($class, config_item('subclass_prefix'), $params, $object_name);   }   // 如果不是扩展,和上面类似   $is_duplicate = FALSE;   foreach ($this->_ci_library_paths as $path)   {    $filepath = $path.'libraries/'.$subdir.$class.'.php';    // Does the file exist?  No?  Bummer...    if ( ! file_exists($filepath))    {     continue;    }    // Safety:  Was the class already loaded by a previous call?    if (in_array($filepath, $this->_ci_loaded_files))    {     // Before we deem this to be a duplicate request, let's see     // if a custom object name is being supplied.  If so, we'll     // return a new instance of the object     if ( ! is_null($object_name))     {      $CI =& get_instance();      if ( ! isset($CI->$object_name))      {       return $this->_ci_init_class($class, '', $params, $object_name);      }     }     $is_duplicate = TRUE;     log_message('debug', $class." class already loaded. Second attempt ignored.");     return;    }    include_once($filepath);    $this->_ci_loaded_files[] = $filepath;    return $this->_ci_init_class($class, '', $params, $object_name);   }  } // END FOREACH  // 如果还没有找到该class,最后的尝试是该class会不会在同名的子目录下  if ($subdir == '')  {   $path = strtolower($class).'/'.$class;   return $this->_ci_load_class($path, $params);  }  // 加载失败,报错  if ($is_duplicate == FALSE)  {   log_message('error', "Unable to load the requested class: ".$class);   show_error("Unable to load the requested class: ".$class);  } } // -------------------------------------------------------------------- /**  * 实例化已经加载的类  */ protected function _ci_init_class($class, $prefix = '', $config = FALSE, $object_name = NULL) {  // 是否有类的配置信息  if ($config === NULL)  {   // Fetch the config paths containing any package paths   $config_component = $this->_ci_get_component('config');   if (is_array($config_component->_config_paths))   {    // Break on the first found file, thus package files    // are not overridden by default paths    foreach ($config_component->_config_paths as $path)    {     // We test for both uppercase and lowercase, for servers that     // are case-sensitive with regard to file names. Check for environment     // first, global next     if (defined('ENVIRONMENT') AND file_exists($path .'config/'.ENVIRONMENT.'/'.strtolower($class).'.php'))     {      include($path .'config/'.ENVIRONMENT.'/'.strtolower($class).'.php');      break;     }     elseif (defined('ENVIRONMENT') AND file_exists($path .'config/'.ENVIRONMENT.'/'.ucfirst(strtolower($class)).'.php'))     {      include($path .'config/'.ENVIRONMENT.'/'.ucfirst(strtolower($class)).'.php');      break;     }     elseif (file_exists($path .'config/'.strtolower($class).'.php'))     {      include($path .'config/'.strtolower($class).'.php');      break;     }     elseif (file_exists($path .'config/'.ucfirst(strtolower($class)).'.php'))     {      include($path .'config/'.ucfirst(strtolower($class)).'.php');      break;     }    }   }  }  if ($prefix == '')  {       //system下library   if (class_exists('CI_'.$class))   {    $name = 'CI_'.$class;   }   elseif (class_exists(config_item('subclass_prefix').$class))   {       //扩展library    $name = config_item('subclass_prefix').$class;   }   else   {    $name = $class;   }  }  else  {   $name = $prefix.$class;  }  // Is the class name valid?  if ( ! class_exists($name))  {   log_message('error', "Non-existent class: ".$name);   show_error("Non-existent class: ".$class);  }  // Set the variable name we will assign the class to  // Was a custom class name supplied?  If so we'll use it  $class = strtolower($class);  if (is_null($object_name))  {   $classvar = ( ! isset($this->_ci_varmap[$class])) ? $class : $this->_ci_varmap[$class];  }  else  {   $classvar = $object_name;  }  // Save the class name and object name  $this->_ci_classes[$class] = $classvar;  // 将初始化的类的实例给CI超级句柄  $CI =& get_instance();  if ($config !== NULL)  {   $CI->$classvar = new $name($config);  }  else  {   $CI->$classvar = new $name;  } } // -------------------------------------------------------------------- /**  * 自动加载器 *  * autoload.php配置的自动加载文件有: *  | 1. Packages    | 2. Libraries    | 3. Helper files    | 4. Custom config files    | 5. Language files    | 6. Models  */ private function _ci_autoloader() {  if (defined('ENVIRONMENT') AND file_exists(APPPATH.'config/'.ENVIRONMENT.'/autoload.php'))  {   include(APPPATH.'config/'.ENVIRONMENT.'/autoload.php');  }  else  {   include(APPPATH.'config/autoload.php');  }  if ( ! isset($autoload))  {   return FALSE;  }  // 自动加载packages,也就是将package_path加入到library,model,helper,config  if (isset($autoload['packages']))  {   foreach ($autoload['packages'] as $package_path)   {    $this->add_package_path($package_path);   }  }  // 加载config文件  if (count($autoload['config']) > 0)  {   $CI =& get_instance();   foreach ($autoload['config'] as $key => $val)   {    $CI->config->load($val);   }  }  // 加载helper和language  foreach (array('helper', 'language') as $type)  {   if (isset($autoload[$type]) AND count($autoload[$type]) > 0)   {    $this->$type($autoload[$type]);   }  }  // 这个好像是为了兼容以前版本的  if ( ! isset($autoload['libraries']) AND isset($autoload['core']))  {   $autoload['libraries'] = $autoload['core'];  }  // 加载libraries  if (isset($autoload['libraries']) AND count($autoload['libraries']) > 0)  {   // 加载db   if (in_array('database', $autoload['libraries']))   {    $this->database();    $autoload['libraries'] = array_diff($autoload['libraries'], array('database'));   }   // 加载所有其他libraries   foreach ($autoload['libraries'] as $item)   {    $this->library($item);   }  }  // Autoload models  if (isset($autoload['model']))  {   $this->model($autoload['model']);  } } // -------------------------------------------------------------------- /**  * 返回由对象属性组成的关联数组  */ protected function _ci_object_to_array($object) {  return (is_object($object)) ? get_object_vars($object) : $object; } // -------------------------------------------------------------------- /**  * 获取CI某个组件的实例  */ protected function &_ci_get_component($component) {  $CI =& get_instance();  return $CI->$component; } // -------------------------------------------------------------------- /**  * 处理文件名,这个函数主要是返回正确文件名  */ protected function _ci_prep_filename($filename, $extension) {  if ( ! is_array($filename))  {   return array(strtolower(str_replace('.php', '', str_replace($extension, '', $filename)).$extension));  }  else  {   foreach ($filename as $key => $val)   {    $filename[$key] = strtolower(str_replace('.php', '', str_replace($extension, '', $val)).$extension);   }   return $filename;  } }}

以上是云栖社区小编为您精心准备的的内容,在云栖社区的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索框架 , 源码 , 分析 装载 ,以便于您获取更多的相关知识。