手机
当前位置:查字典教程网 >编程开发 >php教程 >CI框架装载器Loader.php源码分析
CI框架装载器Loader.php源码分析
摘要:顾名思义,装载器就是加载元素的,使用CI时,经常加载的有:$this->load->library()$this->load->view()...

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

$this->load->library()

$this->load->view()

$this->load->model()

$this->load->database()

$this->load->helper()

$this->load->config()

$this->load->add_package_path()

复制代码 代码如下:

/**

* Loader Class

*

* 用户加载views和files,常见的函数有model(),view(),library(),helper()

*

* Controller的好助手,$this->load =& load_class('Loader', 'core');,加载了loader,Controller就无比强大了

*/

class CI_Loader {

protected $_ci_ob_level;

protected $_ci_view_paths= array();

protected $_ci_library_paths= array();

protected $_ci_model_paths= array();

protected $_ci_helper_paths= array();

protected $_base_classes= array(); // Set by the controller class

protected $_ci_cached_vars= array();

protected $_ci_classes= array();

protected $_ci_loaded_files= array();

protected $_ci_models= array();

protected $_ci_helpers= array();

protected $_ci_varmap= array('unit_test' => 'unit',

'user_agent' => 'agent');

public function __construct()

{

//获取缓冲嵌套级别

$this->_ci_ob_level = ob_get_level();

//library路径

$this->_ci_library_paths = array(APPPATH, BASEPATH);

//helper路径

$this->_ci_helper_paths = array(APPPATH, BASEPATH);

//model路径

$this->_ci_model_paths = array(APPPATH);

//view路径

$this->_ci_view_paths = array(APPPATH.'views/'=> TRUE);

log_message('debug', "Loader Class Initialized");

}

// --------------------------------------------------------------------

/**

* 初始化Loader

*

*/

public function initialize()

{

$this->_ci_classes = array();

$this->_ci_loaded_files = array();

$this->_ci_models = array();

//将is_loaded(common中记录加载核心类函数)加载的核心类交给_base_classes

$this->_base_classes =& is_loaded();

//加载autoload.php配置中文件

$this->_ci_autoloader();

return $this;

}

// --------------------------------------------------------------------

/**

* 检测类是否加载

*/

public function is_loaded($class)

{

if (isset($this->_ci_classes[$class]))

{

return $this->_ci_classes[$class];

}

return FALSE;

}

// --------------------------------------------------------------------

/**

* 加载Class

*/

public function library($library = '', $params = NULL, $object_name = NULL)

{

if (is_array($library))

{

foreach ($library as $class)

{

$this->library($class, $params);

}

return;

}

//如果$library为空或者已经加载。。。

if ($library == '' OR isset($this->_base_classes[$library]))

{

return FALSE;

}

if ( ! is_null($params) && ! is_array($params))

{

$params = NULL;

}

$this->_ci_load_class($library, $params, $object_name);

}

// --------------------------------------------------------------------

/**

* 加载和实例化model

*/

public function model($model, $name = '', $db_conn = FALSE)

{

//CI支持数组加载多个model

if (is_array($model))

{

foreach ($model as $babe)

{

$this->model($babe);

}

return;

}

if ($model == '')

{

return;

}

$path = '';

// 是否存在子目录

if (($last_slash = strrpos($model, '/')) !== FALSE)

{

// The path is in front of the last slash

$path = substr($model, 0, $last_slash + 1);

// And the model name behind it

$model = substr($model, $last_slash + 1);

}

if ($name == '')

{

$name = $model;

}

if (in_array($name, $this->_ci_models, TRUE))

{

return;

}

$CI =& get_instance();

if (isset($CI->$name))

{

show_error('The model name you are loading is the name of a resource that is already being used: '.$name);

}

$model = strtolower($model); //model文件名全小写

foreach ($this->_ci_model_paths as $mod_path)

{

if ( ! file_exists($mod_path.'models/'.$path.$model.'.php'))

{

continue;

}

if ($db_conn !== FALSE AND ! class_exists('CI_DB'))

{

if ($db_conn === TRUE)

{

$db_conn = '';

}

$CI->load->database($db_conn, FALSE, TRUE);

}

if ( ! class_exists('CI_Model'))

{

load_class('Model', 'core');

}

require_once($mod_path.'models/'.$path.$model.'.php');

$model = ucfirst($model);

$CI->$name = new $model();

//保存在Loader::_ci_models中,以后可以用它来判断某个model是否已经加载过。

$this->_ci_models[] = $name;

return;

}

// couldn't find the model

show_error('Unable to locate the model you have specified: '.$model);

}

// --------------------------------------------------------------------

/**

* 数据库Loader

*/

public function database($params = '', $return = FALSE, $active_record = NULL)

{

// Grab the super object

$CI =& get_instance();

// 是否需要加载db

if (class_exists('CI_DB') AND $return == FALSE AND $active_record == NULL AND isset($CI->db) AND is_object($CI->db))

{

return FALSE;

}

require_once(BASEPATH.'database/DB.php');

if ($return === TRUE)

{

return DB($params, $active_record);

}

// Initialize the db variable. Needed to prevent

// reference errors with some configurations

$CI->db = '';

// Load the DB class

$CI->db =& DB($params, $active_record);

}

// --------------------------------------------------------------------

/**

* 加载数据库工具类

*/

public function dbutil()

{

if ( ! class_exists('CI_DB'))

{

$this->database();

}

$CI =& get_instance();

// for backwards compatibility, load dbforge so we can extend dbutils off it

// this use is deprecated and strongly discouraged

$CI->load->dbforge();

require_once(BASEPATH.'database/DB_utility.php');

require_once(BASEPATH.'database/drivers/'.$CI->db->dbdriver.'/'.$CI->db->dbdriver.'_utility.php');

$class = 'CI_DB_'.$CI->db->dbdriver.'_utility';

$CI->dbutil = new $class();

}

// --------------------------------------------------------------------

/**

* Load the Database Forge Class

*

* @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路径中加载helper

foreach ($this->_ci_helper_paths as $path)

{

if (file_exists($path.'helpers/'.$helper.'.php'))

{

include_once($path.'helpers/'.$helper.'.php');

$this->_ci_helpers[$helper] = TRUE;

log_message('debug', 'Helper loaded: '.$helper);

break;

}

}

// 如果该helper还没加载成功的话,说明加载helper失败

if ( ! isset($this->_ci_helpers[$helper]))

{

show_error('Unable to load the requested file: helpers/'.$helper.'.php');

}

}

}

// --------------------------------------------------------------------

/**

* 可以看到helpers调用也是上面的helper,只是helpers的别名而已

*/

public function helpers($helpers = array())

{

$this->helper($helpers);

}

// --------------------------------------------------------------------

/**

* 加载language文件

*/

public function language($file = array(), $lang = '')

{

$CI =& get_instance();

if ( ! is_array($file))

{

$file = array($file);

}

foreach ($file as $langfile)

{

$CI->lang->load($langfile, $lang);

}

}

// --------------------------------------------------------------------

/**

* 加载配置文件

*/

public function config($file = '', $use_sections = FALSE, $fail_gracefully = FALSE)

{

$CI =& get_instance();

$CI->config->load($file, $use_sections, $fail_gracefully);

}

// --------------------------------------------------------------------

/**

* Driver

*

* 加载 driver library

*/

public function driver($library = '', $params = NULL, $object_name = NULL)

{

if ( ! class_exists('CI_Driver_Library'))

{

// we aren't instantiating an object here, that'll be done by the Library itself

require BASEPATH.'libraries/Driver.php';

}

if ($library == '')

{

return FALSE;

}

// We can save the loader some time since Drivers will *always* be in a subfolder,

// and typically identically named to the library

if ( ! strpos($library, '/'))

{

$library = ucfirst($library).'/'.$library;

}

return $this->library($library, $params, $object_name);

}

// --------------------------------------------------------------------

/**

* 添加 Package 路径

*

* 把package路径添加到库,模型,助手,配置路径

*/

public function add_package_path($path, $view_cascade=TRUE)

{

$path = rtrim($path, '/').'/';

array_unshift($this->_ci_library_paths, $path);

array_unshift($this->_ci_model_paths, $path);

array_unshift($this->_ci_helper_paths, $path);

$this->_ci_view_paths = array($path.'views/' => $view_cascade) + $this->_ci_view_paths;

$config =& $this->_ci_get_component('config');

array_unshift($config->_config_paths, $path);

}

// --------------------------------------------------------------------

/**

* 获取Package Paths,默认不包含BASEPATH

*/

public function get_package_paths($include_base = FALSE)

{

return $include_base === TRUE ? $this->_ci_library_paths : $this->_ci_model_paths;

}

// --------------------------------------------------------------------

/**

* 剔除Package Path

*

* Remove a path from the library, model, and helper path arrays if it exists

* If no path is provided, the most recently added path is removed.

*

*/

public function remove_package_path($path = '', $remove_config_path = TRUE)

{

$config =& $this->_ci_get_component('config');

if ($path == '')

{

$void = array_shift($this->_ci_library_paths);

$void = array_shift($this->_ci_model_paths);

$void = array_shift($this->_ci_helper_paths);

$void = array_shift($this->_ci_view_paths);

$void = array_shift($config->_config_paths);

}

else

{

$path = rtrim($path, '/').'/';

foreach (array('_ci_library_paths', '_ci_model_paths', '_ci_helper_paths') as $var)

{

if (($key = array_search($path, $this->{$var})) !== FALSE)

{

unset($this->{$var}[$key]);

}

}

if (isset($this->_ci_view_paths[$path.'views/']))

{

unset($this->_ci_view_paths[$path.'views/']);

}

if (($key = array_search($path, $config->_config_paths)) !== FALSE)

{

unset($config->_config_paths[$key]);

}

}

// 保证应用默认的路径依然存在

$this->_ci_library_paths = array_unique(array_merge($this->_ci_library_paths, array(APPPATH, BASEPATH)));

$this->_ci_helper_paths = array_unique(array_merge($this->_ci_helper_paths, array(APPPATH, BASEPATH)));

$this->_ci_model_paths = array_unique(array_merge($this->_ci_model_paths, array(APPPATH)));

$this->_ci_view_paths = array_merge($this->_ci_view_paths, array(APPPATH.'views/' => TRUE));

$config->_config_paths = array_unique(array_merge($config->_config_paths, array(APPPATH)));

}

// --------------------------------------------------------------------

/**

* Loader

*

* This function is used to load views and files.

* Variables are prefixed with _ci_ to avoid symbol collision with

* variables made available to view files

*

* @paramarray

* @returnvoid

*/

protected function _ci_load($_ci_data)

{

// Set the default data variables

foreach (array('_ci_view', '_ci_vars', '_ci_path', '_ci_return') as $_ci_val)

{

$$_ci_val = ( ! isset($_ci_data[$_ci_val])) ? FALSE : $_ci_data[$_ci_val];

}

$file_exists = FALSE;

//如果$_ci_path不为空,则说明当前要加载普通文件。Loader::file才会有path

if ($_ci_path != '')

{

$_ci_x = explode('/', $_ci_path);

$_ci_file = end($_ci_x);

}

else

{

$_ci_ext = pathinfo($_ci_view, PATHINFO_EXTENSION);

$_ci_file = ($_ci_ext == '') ? $_ci_view.'.php' : $_ci_view;

foreach ($this->_ci_view_paths as $view_file => $cascade)

{

if (file_exists($view_file.$_ci_file))

{

$_ci_path = $view_file.$_ci_file;

$file_exists = TRUE;

break;

}

if ( ! $cascade)

{

break;

}

}

}

//view文件不存在则会报错

if ( ! $file_exists && ! file_exists($_ci_path))

{

show_error('Unable to load the requested file: '.$_ci_file);

}

// 把CI的所有属性都传递给loader,view中$this指的是loader

$_ci_CI =& get_instance();

foreach (get_object_vars($_ci_CI) as $_ci_key => $_ci_var)

{

if ( ! isset($this->$_ci_key))

{

$this->$_ci_key =& $_ci_CI->$_ci_key;

}

}

/*

* Extract and cache variables

*

* You can either set variables using the dedicated $this->load_vars()

* function or via the second parameter of this function. We'll merge

* the two types and cache them so that views that are embedded within

* other views can have access to these variables.

*/

if (is_array($_ci_vars))

{

$this->_ci_cached_vars = array_merge($this->_ci_cached_vars, $_ci_vars);

}

extract($this->_ci_cached_vars);

/*

* 将视图内容放到缓存区

*

*/

ob_start();

// 支持短标签

if ((bool) @ini_get('short_open_tag') === FALSE AND config_item('rewrite_short_tags') == TRUE)

{

echo eval('?>'.preg_replace("/;*s*"; ", str_replace('<?=', '<?php echo ', file_get_contents($_ci_path))));

}

else

{

include($_ci_path); // include() vs include_once() allows for multiple views with the same name

}

log_message('debug', 'File loaded: '.$_ci_path);

// 是否直接返回view数据

if ($_ci_return === TRUE)

{

$buffer = ob_get_contents();

@ob_end_clean();

return $buffer;

}

//当前这个视图文件是被另一个视图文件通过$this->view()方法引入,即视图文件嵌入视图文件

if (ob_get_level() > $this->_ci_ob_level + 1)

{

ob_end_flush();

}

else

{ ////把缓冲区的内容交给Output组件并清空关闭缓冲区。

$_ci_CI->output->append_output(ob_get_contents());

@ob_end_clean();

}

}

// --------------------------------------------------------------------

/**

* 加载类

*/

protected function _ci_load_class($class, $params = NULL, $object_name = NULL)

{

// 去掉.php和两端的/获取的$class就是类名或目录名+类名

$class = str_replace('.php', '', trim($class, '/'));

// CI允许dir/filename方式

$subdir = '';

if (($last_slash = strrpos($class, '/')) !== FALSE)

{

// 目录

$subdir = substr($class, 0, $last_slash + 1);

// 文件名

$class = substr($class, $last_slash + 1);

}

// 允许加载的类名首字母大写或全小写

foreach (array(ucfirst($class), strtolower($class)) as $class)

{

$subclass = APPPATH.'libraries/'.$subdir.config_item('subclass_prefix').$class.'.php';

// 是否是扩展类

if (file_exists($subclass))

{

$baseclass = BASEPATH.'libraries/'.ucfirst($class).'.php';

if ( ! file_exists($baseclass))

{

log_message('error', "Unable to load the requested class: ".$class);

show_error("Unable to load the requested class: ".$class);

}

// Safety: Was the class already loaded by a previous call?

if (in_array($subclass, $this->_ci_loaded_files))

{

// Before we deem this to be a duplicate request, let's see

// if a custom object name is being supplied. If so, we'll

// return a new instance of the object

if ( ! is_null($object_name))

{

$CI =& get_instance();

if ( ! isset($CI->$object_name))

{

return $this->_ci_init_class($class, config_item('subclass_prefix'), $params, $object_name);

}

}

$is_duplicate = TRUE;

log_message('debug', $class." class already loaded. Second attempt ignored.");

return;

}

include_once($baseclass);

include_once($subclass);

$this->_ci_loaded_files[] = $subclass;

//实例化类

return $this->_ci_init_class($class, config_item('subclass_prefix'), $params, $object_name);

}

// 如果不是扩展,和上面类似

$is_duplicate = FALSE;

foreach ($this->_ci_library_paths as $path)

{

$filepath = $path.'libraries/'.$subdir.$class.'.php';

// Does the file exist? No? Bummer...

if ( ! file_exists($filepath))

{

continue;

}

// Safety: Was the class already loaded by a previous call?

if (in_array($filepath, $this->_ci_loaded_files))

{

// Before we deem this to be a duplicate request, let's see

// if a custom object name is being supplied. If so, we'll

// return a new instance of the object

if ( ! is_null($object_name))

{

$CI =& get_instance();

if ( ! isset($CI->$object_name))

{

return $this->_ci_init_class($class, '', $params, $object_name);

}

}

$is_duplicate = TRUE;

log_message('debug', $class." class already loaded. Second attempt ignored.");

return;

}

include_once($filepath);

$this->_ci_loaded_files[] = $filepath;

return $this->_ci_init_class($class, '', $params, $object_name);

}

} // END FOREACH

// 如果还没有找到该class,最后的尝试是该class会不会在同名的子目录下

if ($subdir == '')

{

$path = strtolower($class).'/'.$class;

return $this->_ci_load_class($path, $params);

}

// 加载失败,报错

if ($is_duplicate == FALSE)

{

log_message('error', "Unable to load the requested class: ".$class);

show_error("Unable to load the requested class: ".$class);

}

}

// --------------------------------------------------------------------

/**

* 实例化已经加载的类

*/

protected function _ci_init_class($class, $prefix = '', $config = FALSE, $object_name = NULL)

{

// 是否有类的配置信息

if ($config === NULL)

{

// Fetch the config paths containing any package paths

$config_component = $this->_ci_get_component('config');

if (is_array($config_component->_config_paths))

{

// Break on the first found file, thus package files

// are not overridden by default paths

foreach ($config_component->_config_paths as $path)

{

// We test for both uppercase and lowercase, for servers that

// are case-sensitive with regard to file names. Check for environment

// first, global next

if (defined('ENVIRONMENT') AND file_exists($path .'config/'.ENVIRONMENT.'/'.strtolower($class).'.php'))

{

include($path .'config/'.ENVIRONMENT.'/'.strtolower($class).'.php');

break;

}

elseif (defined('ENVIRONMENT') AND file_exists($path .'config/'.ENVIRONMENT.'/'.ucfirst(strtolower($class)).'.php'))

{

include($path .'config/'.ENVIRONMENT.'/'.ucfirst(strtolower($class)).'.php');

break;

}

elseif (file_exists($path .'config/'.strtolower($class).'.php'))

{

include($path .'config/'.strtolower($class).'.php');

break;

}

elseif (file_exists($path .'config/'.ucfirst(strtolower($class)).'.php'))

{

include($path .'config/'.ucfirst(strtolower($class)).'.php');

break;

}

}

}

}

if ($prefix == '')

{ //system下library

if (class_exists('CI_'.$class))

{

$name = 'CI_'.$class;

}

elseif (class_exists(config_item('subclass_prefix').$class))

{ //扩展library

$name = config_item('subclass_prefix').$class;

}

else

{

$name = $class;

}

}

else

{

$name = $prefix.$class;

}

// Is the class name valid?

if ( ! class_exists($name))

{

log_message('error', "Non-existent class: ".$name);

show_error("Non-existent class: ".$class);

}

// Set the variable name we will assign the class to

// Was a custom class name supplied? If so we'll use it

$class = strtolower($class);

if (is_null($object_name))

{

$classvar = ( ! isset($this->_ci_varmap[$class])) ? $class : $this->_ci_varmap[$class];

}

else

{

$classvar = $object_name;

}

// Save the class name and object name

$this->_ci_classes[$class] = $classvar;

// 将初始化的类的实例给CI超级句柄

$CI =& get_instance();

if ($config !== NULL)

{

$CI->$classvar = new $name($config);

}

else

{

$CI->$classvar = new $name;

}

}

// --------------------------------------------------------------------

/**

* 自动加载器

*

* autoload.php配置的自动加载文件有:

* | 1. Packages

| 2. Libraries

| 3. Helper files

| 4. Custom config files

| 5. Language files

| 6. Models

*/

private function _ci_autoloader()

{

if (defined('ENVIRONMENT') AND file_exists(APPPATH.'config/'.ENVIRONMENT.'/autoload.php'))

{

include(APPPATH.'config/'.ENVIRONMENT.'/autoload.php');

}

else

{

include(APPPATH.'config/autoload.php');

}

if ( ! isset($autoload))

{

return FALSE;

}

// 自动加载packages,也就是将package_path加入到library,model,helper,config

if (isset($autoload['packages']))

{

foreach ($autoload['packages'] as $package_path)

{

$this->add_package_path($package_path);

}

}

// 加载config文件

if (count($autoload['config']) > 0)

{

$CI =& get_instance();

foreach ($autoload['config'] as $key => $val)

{

$CI->config->load($val);

}

}

// 加载helper和language

foreach (array('helper', 'language') as $type)

{

if (isset($autoload[$type]) AND count($autoload[$type]) > 0)

{

$this->$type($autoload[$type]);

}

}

// 这个好像是为了兼容以前版本的

if ( ! isset($autoload['libraries']) AND isset($autoload['core']))

{

$autoload['libraries'] = $autoload['core'];

}

// 加载libraries

if (isset($autoload['libraries']) AND count($autoload['libraries']) > 0)

{

// 加载db

if (in_array('database', $autoload['libraries']))

{

$this->database();

$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));

}

// 加载所有其他libraries

foreach ($autoload['libraries'] as $item)

{

$this->library($item);

}

}

// Autoload models

if (isset($autoload['model']))

{

$this->model($autoload['model']);

}

}

// --------------------------------------------------------------------

/**

* 返回由对象属性组成的关联数组

*/

protected function _ci_object_to_array($object)

{

return (is_object($object)) ? get_object_vars($object) : $object;

}

// --------------------------------------------------------------------

/**

* 获取CI某个组件的实例

*/

protected function &_ci_get_component($component)

{

$CI =& get_instance();

return $CI->$component;

}

// --------------------------------------------------------------------

/**

* 处理文件名,这个函数主要是返回正确文件名

*/

protected function _ci_prep_filename($filename, $extension)

{

if ( ! is_array($filename))

{

return array(strtolower(str_replace('.php', '', str_replace($extension, '', $filename)).$extension));

}

else

{

foreach ($filename as $key => $val)

{

$filename[$key] = strtolower(str_replace('.php', '', str_replace($extension, '', $val)).$extension);

}

return $filename;

}

}

}

【CI框架装载器Loader.php源码分析】相关文章:

php备份数据库类分享

漂亮但不安全的CTB

用PHP代码给图片加水印

Search Engine Friendly的URL设计

PHP中preg_match函数正则匹配的字符串长度问题

十天学会php之第六天

PHP超牛逼无限极分类生成树方法

PHP下MAIL的另一解决方案

一个程序下载的管理程序(二)

计数器详细设计

精品推荐
分类导航