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()
/**
*LoaderClass
*
*用户加载views和files,常见的函数有model(),view(),library(),helper()
*
*Controller的好助手,$this->load=&load_class('Loader','core');,加载了loader,Controller就无比强大了
*/
classCI_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();//Setbythecontrollerclass
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');
publicfunction__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',"LoaderClassInitialized");
}
//--------------------------------------------------------------------
/**
*初始化Loader
*
*/
publicfunctioninitialize()
{
$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;
}
//--------------------------------------------------------------------
/**
*检测类是否加载
*/
publicfunctionis_loaded($class)
{
if(isset($this->_ci_classes[$class]))
{
return$this->_ci_classes[$class];
}
returnFALSE;
}
//--------------------------------------------------------------------
/**
*加载Class
*/
publicfunctionlibrary($library='',$params=NULL,$object_name=NULL)
{
if(is_array($library))
{
foreach($libraryas$class)
{
$this->library($class,$params);
}
return;
}
//如果$library为空或者已经加载。。。
if($library==''ORisset($this->_base_classes[$library]))
{
returnFALSE;
}
if(!is_null($params)&&!is_array($params))
{
$params=NULL;
}
$this->_ci_load_class($library,$params,$object_name);
}
//--------------------------------------------------------------------
/**
*加载和实例化model
*/
publicfunctionmodel($model,$name='',$db_conn=FALSE)
{
//CI支持数组加载多个model
if(is_array($model))
{
foreach($modelas$babe)
{
$this->model($babe);
}
return;
}
if($model=='')
{
return;
}
$path='';
//是否存在子目录
if(($last_slash=strrpos($model,'/'))!==FALSE)
{
//Thepathisinfrontofthelastslash
$path=substr($model,0,$last_slash+1);
//Andthemodelnamebehindit
$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('Themodelnameyouareloadingisthenameofaresourcethatisalreadybeingused:'.$name);
}
$model=strtolower($model);//model文件名全小写
foreach($this->_ci_model_pathsas$mod_path)
{
if(!file_exists($mod_path.'models/'.$path.$model.'.php'))
{
continue;
}
if($db_conn!==FALSEAND!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'tfindthemodel
show_error('Unabletolocatethemodelyouhavespecified:'.$model);
}
//--------------------------------------------------------------------
/**
*数据库Loader
*/
publicfunctiondatabase($params='',$return=FALSE,$active_record=NULL)
{
//Grabthesuperobject
$CI=&get_instance();
//是否需要加载db
if(class_exists('CI_DB')AND$return==FALSEAND$active_record==NULLANDisset($CI->db)ANDis_object($CI->db))
{
returnFALSE;
}
require_once(BASEPATH.'database/DB.php');
if($return===TRUE)
{
returnDB($params,$active_record);
}
//Initializethedbvariable. Neededtoprevent
//referenceerrorswithsomeconfigurations
$CI->db='';
//LoadtheDBclass
$CI->db=&DB($params,$active_record);
}
//--------------------------------------------------------------------
/**
*加载数据库工具类
*/
publicfunctiondbutil()
{
if(!class_exists('CI_DB'))
{
$this->database();
}
$CI=&get_instance();
//forbackwardscompatibility,loaddbforgesowecanextenddbutilsoffit
//thisuseisdeprecatedandstronglydiscouraged
$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();
}
//--------------------------------------------------------------------
/**
*LoadtheDatabaseForgeClass
*
*@return string
*/
publicfunctiondbforge()
{
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();
}
//--------------------------------------------------------------------
/**
*加载视图文件
*/
publicfunctionview($view,$vars=array(),$return=FALSE)
{
return$this->_ci_load(array('_ci_view'=>$view,'_ci_vars'=>$this->_ci_object_to_array($vars),'_ci_return'=>$return));
}
//--------------------------------------------------------------------
/**
*加载普通文件
*/
publicfunctionfile($path,$return=FALSE)
{
return$this->_ci_load(array('_ci_path'=>$path,'_ci_return'=>$return));
}
//--------------------------------------------------------------------
/**
*设置变量
*
*Oncevariablesaresettheybecomeavailablewithin
*thecontrollerclassandits"view"files.
*
*/
publicfunctionvars($vars=array(),$val='')
{
if($val!=''ANDis_string($vars))
{
$vars=array($vars=>$val);
}
$vars=$this->_ci_object_to_array($vars);
if(is_array($vars)ANDcount($vars)>0)
{
foreach($varsas$key=>$val)
{
$this->_ci_cached_vars[$key]=$val;
}
}
}
//--------------------------------------------------------------------
/**
*检查并获取变量
*/
publicfunctionget_var($key)
{
returnisset($this->_ci_cached_vars[$key])?$this->_ci_cached_vars[$key]:NULL;
}
//--------------------------------------------------------------------
/**
*加载helper
*/
publicfunctionhelper($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('Unabletoloadtherequestedfile:helpers/'.$helper.'.php');
}
include_once($ext_helper);
include_once($base_helper);
$this->_ci_helpers[$helper]=TRUE;
log_message('debug','Helperloaded:'.$helper);
continue;
}
//如果不是扩展helper,helper路径中加载helper
foreach($this->_ci_helper_pathsas$path)
{
if(file_exists($path.'helpers/'.$helper.'.php'))
{
include_once($path.'helpers/'.$helper.'.php');
$this->_ci_helpers[$helper]=TRUE;
log_message('debug','Helperloaded:'.$helper);
break;
}
}
//如果该helper还没加载成功的话,说明加载helper失败
if(!isset($this->_ci_helpers[$helper]))
{
show_error('Unabletoloadtherequestedfile:helpers/'.$helper.'.php');
}
}
}
//--------------------------------------------------------------------
/**
*可以看到helpers调用也是上面的helper,只是helpers的别名而已
*/
publicfunctionhelpers($helpers=array())
{
$this->helper($helpers);
}
//--------------------------------------------------------------------
/**
*加载language文件
*/
publicfunctionlanguage($file=array(),$lang='')
{
$CI=&get_instance();
if(!is_array($file))
{
$file=array($file);
}
foreach($fileas$langfile)
{
$CI->lang->load($langfile,$lang);
}
}
//--------------------------------------------------------------------
/**
*加载配置文件
*/
publicfunctionconfig($file='',$use_sections=FALSE,$fail_gracefully=FALSE)
{
$CI=&get_instance();
$CI->config->load($file,$use_sections,$fail_gracefully);
}
//--------------------------------------------------------------------
/**
*Driver
*
*加载driverlibrary
*/
publicfunctiondriver($library='',$params=NULL,$object_name=NULL)
{
if(!class_exists('CI_Driver_Library'))
{
//wearen'tinstantiatinganobjecthere,that'llbedonebytheLibraryitself
requireBASEPATH.'libraries/Driver.php';
}
if($library=='')
{
returnFALSE;
}
//WecansavetheloadersometimesinceDriverswill*always*beinasubfolder,
//andtypicallyidenticallynamedtothelibrary
if(!strpos($library,'/'))
{
$library=ucfirst($library).'/'.$library;
}
return$this->library($library,$params,$object_name);
}
//--------------------------------------------------------------------
/**
*添加Package路径
*
*把package路径添加到库,模型,助手,配置路径
*/
publicfunctionadd_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);
}
//--------------------------------------------------------------------
/**
*获取PackagePaths,默认不包含BASEPATH
*/
publicfunctionget_package_paths($include_base=FALSE)
{
return$include_base===TRUE?$this->_ci_library_paths:$this->_ci_model_paths;
}
//--------------------------------------------------------------------
/**
*剔除PackagePath
*
*Removeapathfromthelibrary,model,andhelperpatharraysifitexists
*Ifnopathisprovided,themostrecentlyaddedpathisremoved.
*
*/
publicfunctionremove_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
*
*Thisfunctionisusedtoloadviewsandfiles.
*Variablesareprefixedwith_ci_toavoidsymbolcollisionwith
*variablesmadeavailabletoviewfiles
*
*@param array
*@return void
*/
protectedfunction_ci_load($_ci_data)
{
//Setthedefaultdatavariables
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_pathsas$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('Unabletoloadtherequestedfile:'.$_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;
}
}
/*
*Extractandcachevariables
*
*Youcaneithersetvariablesusingthededicated$this->load_vars()
*functionorviathesecondparameterofthisfunction.We'llmerge
*thetwotypesandcachethemsothatviewsthatareembeddedwithin
*otherviewscanhaveaccesstothesevariables.
*/
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')===FALSEANDconfig_item('rewrite_short_tags')==TRUE)
{
echoeval('?>'.preg_replace("/;*\s*\?>/",";?>",str_replace('<?=','<?phpecho',file_get_contents($_ci_path))));
}
else
{
include($_ci_path);//include()vsinclude_once()allowsformultipleviewswiththesamename
}
log_message('debug','Fileloaded:'.$_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();
}
}
//--------------------------------------------------------------------
/**
*加载类
*/
protectedfunction_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',"Unabletoloadtherequestedclass:".$class);
show_error("Unabletoloadtherequestedclass:".$class);
}
//Safety: Wastheclassalreadyloadedbyapreviouscall?
if(in_array($subclass,$this->_ci_loaded_files))
{
//Beforewedeemthistobeaduplicaterequest,let'ssee
//ifacustomobjectnameisbeingsupplied. Ifso,we'll
//returnanewinstanceoftheobject
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."classalreadyloaded.Secondattemptignored.");
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_pathsas$path)
{
$filepath=$path.'libraries/'.$subdir.$class.'.php';
//Doesthefileexist? No? Bummer...
if(!file_exists($filepath))
{
continue;
}
//Safety: Wastheclassalreadyloadedbyapreviouscall?
if(in_array($filepath,$this->_ci_loaded_files))
{
//Beforewedeemthistobeaduplicaterequest,let'ssee
//ifacustomobjectnameisbeingsupplied. Ifso,we'll
//returnanewinstanceoftheobject
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."classalreadyloaded.Secondattemptignored.");
return;
}
include_once($filepath);
$this->_ci_loaded_files[]=$filepath;
return$this->_ci_init_class($class,'',$params,$object_name);
}
}//ENDFOREACH
//如果还没有找到该class,最后的尝试是该class会不会在同名的子目录下
if($subdir=='')
{
$path=strtolower($class).'/'.$class;
return$this->_ci_load_class($path,$params);
}
//加载失败,报错
if($is_duplicate==FALSE)
{
log_message('error',"Unabletoloadtherequestedclass:".$class);
show_error("Unabletoloadtherequestedclass:".$class);
}
}
//--------------------------------------------------------------------
/**
*实例化已经加载的类
*/
protectedfunction_ci_init_class($class,$prefix='',$config=FALSE,$object_name=NULL)
{
//是否有类的配置信息
if($config===NULL)
{
//Fetchtheconfigpathscontaininganypackagepaths
$config_component=$this->_ci_get_component('config');
if(is_array($config_component->_config_paths))
{
//Breakonthefirstfoundfile,thuspackagefiles
//arenotoverriddenbydefaultpaths
foreach($config_component->_config_pathsas$path)
{
//Wetestforbothuppercaseandlowercase,forserversthat
//arecase-sensitivewithregardtofilenames.Checkforenvironment
//first,globalnext
if(defined('ENVIRONMENT')ANDfile_exists($path.'config/'.ENVIRONMENT.'/'.strtolower($class).'.php'))
{
include($path.'config/'.ENVIRONMENT.'/'.strtolower($class).'.php');
break;
}
elseif(defined('ENVIRONMENT')ANDfile_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;
}
//Istheclassnamevalid?
if(!class_exists($name))
{
log_message('error',"Non-existentclass:".$name);
show_error("Non-existentclass:".$class);
}
//Setthevariablenamewewillassigntheclassto
//Wasacustomclassnamesupplied? Ifsowe'lluseit
$class=strtolower($class);
if(is_null($object_name))
{
$classvar=(!isset($this->_ci_varmap[$class]))?$class:$this->_ci_varmap[$class];
}
else
{
$classvar=$object_name;
}
//Savetheclassnameandobjectname
$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.Helperfiles
|4.Customconfigfiles
|5.Languagefiles
|6.Models
*/
privatefunction_ci_autoloader()
{
if(defined('ENVIRONMENT')ANDfile_exists(APPPATH.'config/'.ENVIRONMENT.'/autoload.php'))
{
include(APPPATH.'config/'.ENVIRONMENT.'/autoload.php');
}
else
{
include(APPPATH.'config/autoload.php');
}
if(!isset($autoload))
{
returnFALSE;
}
//自动加载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])ANDcount($autoload[$type])>0)
{
$this->$type($autoload[$type]);
}
}
//这个好像是为了兼容以前版本的
if(!isset($autoload['libraries'])ANDisset($autoload['core']))
{
$autoload['libraries']=$autoload['core'];
}
//加载libraries
if(isset($autoload['libraries'])ANDcount($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);
}
}
//Autoloadmodels
if(isset($autoload['model']))
{
$this->model($autoload['model']);
}
}
//--------------------------------------------------------------------
/**
*返回由对象属性组成的关联数组
*/
protectedfunction_ci_object_to_array($object)
{
return(is_object($object))?get_object_vars($object):$object;
}
//--------------------------------------------------------------------
/**
*获取CI某个组件的实例
*/
protectedfunction&_ci_get_component($component)
{
$CI=&get_instance();
return$CI->$component;
}
//--------------------------------------------------------------------
/**
*处理文件名,这个函数主要是返回正确文件名
*/
protectedfunction_ci_prep_filename($filename,$extension)
{
if(!is_array($filename))
{
returnarray(strtolower(str_replace('.php','',str_replace($extension,'',$filename)).$extension));
}
else
{
foreach($filenameas$key=>$val)
{
$filename[$key]=strtolower(str_replace('.php','',str_replace($extension,'',$val)).$extension);
}
return$filename;
}
}
}