a3322全新 讯网新2代理-南开大学mpacc录取2019

首页

AD联系:507867812

a3322全新 讯网新2代理

时间:2019-11-14 21:46:29 作者:澳门金沙官网一js12345 浏览量:80420

a3322全新 讯网新2代理

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

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

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

,见下图

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

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

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

,见下图

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

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

,如下图

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

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

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

如下图

CI框架装载器Loader.php源码分析,如下图

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

,见图

a3322全新 讯网新2代理

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

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

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

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

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

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

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

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

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

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

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

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

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

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

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

a3322全新 讯网新2代理

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

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

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

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

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

1.

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

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

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

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

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

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

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

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

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

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

2.

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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,configif (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和languageforeach (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'];}// 加载librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// 加载dbif (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// 加载所有其他librariesforeach ($autoload['libraries'] as $item){$this->library($item);}}// Autoload modelsif (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;}}}

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

顾名思义,装载器就是加载元素的,使用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 classprotected $_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支持数组加载多个modelif (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 modelshow_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();// 是否需要加载dbif (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 * * @returnstring */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路径中加载helperforeach ($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 itselfrequire 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 libraryif ( ! 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 * * @paramarray * @returnvoid */protected function _ci_load($_ci_data){// Set the default data variablesforeach (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才会有pathif ($_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 objectif ( ! 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 objectif ( ! 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 pathsforeach ($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 nextif (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下libraryif (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;/