CodeIgniter 核心代码阅读-加载类Loader.php

来源:互联网 发布:普罗米修斯 2知乎 编辑:程序博客网 时间:2024/06/04 19:39

Loader.php--加载文件类

<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');//文件加载类class CI_Loader {// All these are set automatically. Don't mess with them.//输出缓存级别protected $_ci_ob_level;//视图路径protected $_ci_view_paths= array();//库文件路径protected $_ci_library_paths= array();//模型路径protected $_ci_model_paths= array();//helper类路径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();//已加载的helper类protected $_ci_helpers= array();//类名映射protected $_ci_varmap= array('unit_test' => 'unit','user_agent' => 'agent');//构造函数public function __construct(){$this->_ci_ob_level  = ob_get_level();$this->_ci_library_paths = array(APPPATH, BASEPATH);$this->_ci_helper_paths = array(APPPATH, BASEPATH);$this->_ci_model_paths = array(APPPATH);$this->_ci_view_paths = array(APPPATH.'views/'=> TRUE);log_message('debug', "Loader Class Initialized");}//初始化public function initialize(){$this->_ci_classes = array();$this->_ci_loaded_files = array();$this->_ci_models = array();$this->_base_classes =& is_loaded();$this->_ci_autoloader();return $this;}//判断是否已加载指定的类public function is_loaded($class){if (isset($this->_ci_classes[$class])){return $this->_ci_classes[$class];}return FALSE;}//加载并实例化指定类public function library($library = '', $params = NULL, $object_name = NULL){if (is_array($library)){foreach ($library as $class){$this->library($class, $params);}return;}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);}//加载并实例化指定模型public function model($model, $name = '', $db_conn = FALSE){if (is_array($model)){foreach ($model as $babe){$this->model($babe);}return;}if ($model == ''){return;}$path = '';// Is the model in a sub-folder? If so, parse out the filename and 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);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();$this->_ci_models[] = $name;return;}// couldn't find the modelshow_error('Unable to locate the model you have specified: '.$model);}//加载数据库类public function database($params = '', $return = FALSE, $active_record = NULL){// Grab the super object$CI =& get_instance();// Do we even need to load the database class?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();}//加载并实例化数据定制类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));}//设置变量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';// Is this a helper extension request?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;}// Try to load the 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;}}// unable to load the helperif ( ! isset($this->_ci_helpers[$helper])){show_error('Unable to load the requested file: helpers/'.$helper.'.php');}}}//helper的别名public function helpers($helpers = array()){$this->helper($helpers);}//加载语言包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);}//加载驱动文件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);}//添加包路径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;// Add config file path$config =& $this->_ci_get_component('config');array_unshift($config->_config_paths, $path);}//获取包路径public function get_package_paths($include_base = FALSE){return $include_base === TRUE ? $this->_ci_library_paths : $this->_ci_model_paths;}//删除包路径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]);}}// make sure the application default paths are still in the array$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)));}//文件加载函数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;// Set the path to the requested fileif ($_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;}}}if ( ! $file_exists && ! file_exists($_ci_path)){show_error('Unable to load the requested file: '.$_ci_file);}// This allows anything loaded using $this->load (views, files, etc.)// to become accessible from within the Controller and Model functions.$_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);/* * Buffer the output * * We buffer the output for two reasons: * 1. Speed. You get a significant speed boost. * 2. So that the final rendered template can be * post-processed by the output class.  Why do we * need post processing?  For one thing, in order to * show the elapsed page load time.  Unless we * can intercept the content right before it's sent to * the browser and then stop the timer it won't be accurate. */ob_start();// If the PHP installation does not support short tags we'll// do a little string replacement, changing the short tags// to standard PHP echo statements.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);// Return the file data if requestedif ($_ci_return === TRUE){$buffer = ob_get_contents();@ob_end_clean();return $buffer;}/* * Flush the buffer... or buff the flusher? * * In order to permit views to be nested within * other views, we need to flush the content back out whenever * we are beyond the first level of output buffering so that * it can be seen and included properly by the first included * template and any subsequent ones. Oy! * */if (ob_get_level() > $this->_ci_ob_level + 1){ob_end_flush();}else{$_ci_CI->output->append_output(ob_get_contents());@ob_end_clean();}}//类加载函数protected function _ci_load_class($class, $params = NULL, $object_name = NULL){// Get the class name, and while we're at it trim any slashes.// The directory path can be included as part of the class name,// but we don't want a leading slash$class = str_replace('.php', '', trim($class, '/'));// Was the path included with the class name?// We look for a slash to determine this$subdir = '';if (($last_slash = strrpos($class, '/')) !== FALSE){// Extract the path$subdir = substr($class, 0, $last_slash + 1);// Get the filename from the path$class = substr($class, $last_slash + 1);}// We'll test for both lowercase and capitalized versions of the file nameforeach (array(ucfirst($class), strtolower($class)) as $class){$subclass = APPPATH.'libraries/'.$subdir.config_item('subclass_prefix').$class.'.php';// Is this a class extension request?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);}// Lets search for the requested library file and load it.$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// One last attempt.  Maybe the library is in a subdirectory, but it wasn't specified?if ($subdir == ''){$path = strtolower($class).'/'.$class;return $this->_ci_load_class($path, $params);}// If we got this far we were unable to find the requested class.// We do not issue errors if the load call failed due to a duplicate requestif ($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){// Is there an associated config file for this class?  Note: these should always be lowercaseif ($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 == ''){if (class_exists('CI_'.$class)){$name = 'CI_'.$class;}elseif (class_exists(config_item('subclass_prefix').$class)){$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;// Instantiate the class$CI =& get_instance();if ($config !== NULL){$CI->$classvar = new $name($config);}else{$CI->$classvar = new $name;}}//自动加载类函数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;}// Autoload packagesif (isset($autoload['packages'])){foreach ($autoload['packages'] as $package_path){$this->add_package_path($package_path);}}// Load any custom config fileif (count($autoload['config']) > 0){$CI =& get_instance();foreach ($autoload['config'] as $key => $val){$CI->config->load($val);}}// Autoload helpers and languagesforeach (array('helper', 'language') as $type){if (isset($autoload[$type]) AND count($autoload[$type]) > 0){$this->$type($autoload[$type]);}}// A little tweak to remain backward compatible// The $autoload['core'] item was deprecatedif ( ! isset($autoload['libraries']) AND isset($autoload['core'])){$autoload['libraries'] = $autoload['core'];}// Load librariesif (isset($autoload['libraries']) AND count($autoload['libraries']) > 0){// Load the database driver.if (in_array('database', $autoload['libraries'])){$this->database();$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));}// Load all other 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;}//获取指定库文件或者模型的应用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;}}}


原创粉丝点击