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; } } }