Zend Framework教程之Loader以及PluginLoader用法详解
本文实例分析了ZendFramework中Loader以及PluginLoader用法。分享给大家供大家参考,具体如下:
ZendFramework提供了Zend_Loader,用来动态加载文件。
以下是具体用法,以及具体实现:
1.加载文件
使用方法:
Zend_Loader::loadFile($filename,$dirs=null,$once=false);
具体实现:
/**
*LoadsaPHPfile.ThisisawrapperforPHP'sinclude()function.
*
*$filenamemustbethecompletefilename,includingany
*extensionsuchas".php".Notethatasecuritycheckisperformedthat
*doesnotpermitextendedcharactersinthefilename.Thismethodis
*intendedforloadingZendFrameworkfiles.
*
*If$dirsisastringoranarray,itwillsearchthedirectories
*intheordersupplied,andattempttoloadthefirstmatchingfile.
*
*Ifthefilewasnotfoundinthe$dirs,orifno$dirswerespecified,
*itwillattempttoloaditfromPHP'sinclude_path.
*
*If$onceisTRUE,itwilluseinclude_once()insteadofinclude().
*
*@paramstring$filename
*@paramstring|array$dirs-OPTIONALeitherapathorarrayofpaths
*tosearch.
*@paramboolean$once
*@returnboolean
*@throwsZend_Exception
*/
publicstaticfunctionloadFile($filename,$dirs=null,$once=false)
{
self::_securityCheck($filename);
/**
*Searchinprovideddirectories,aswellasinclude_path
*/
$incPath=false;
if(!empty($dirs)&&(is_array($dirs)||is_string($dirs))){
if(is_array($dirs)){
$dirs=implode(PATH_SEPARATOR,$dirs);
}
$incPath=get_include_path();
set_include_path($dirs.PATH_SEPARATOR.$incPath);
}
/**
*Tryfindingfortheplainfilenameintheinclude_path.
*/
if($once){
include_once$filename;
}else{
include$filename;
}
/**
*Ifsearchingindirectories,resetinclude_path
*/
if($incPath){
set_include_path($incPath);
}
returntrue;
}
参数规则:
正如实现方法,有如下参数
$filename参数指定需要加载的文件,注意$filename不需要指定任何路径,只需要文件名即可。ZF会对文件作安全性检查。$filename只能由字母,数字,连接符-,下划线_及英文句号.组成(半角)。$dirs参数则不限,可以使用中文等。
$dirs参数用来指定文件所在目录,可以是一个字符串或者数组。如果为NULL,则程序将会到系统的include_path下寻找文件是否存在(include_path可在php.ini中设置--Haohappy注),如果是字符串或数组,则会到指定的目录下去找,然后才是include_path。
$once参数为布尔类型,如果为TRUE,Zend_Loader::loadFile()使用PHP函数»include_once()加载文件,否则就是PHP函数»include()。(本参数只能是true或false,两者区别就和include()和include_once()的区别一样。)
2.加载类
具体使用:
Zend_Loader::loadClass('Container_Tree',
array(
'/home/production/mylib',
'/home/production/myapp'
)
);
具体实现:
/**
*LoadsaclassfromaPHPfile.Thefilenamemustbeformatted
*as"$class.php".
*
*If$dirsisastringoranarray,itwillsearchthedirectories
*intheordersupplied,andattempttoloadthefirstmatchingfile.
*
*If$dirsisnull,itwillsplittheclassnameatunderscoresto
*generateapathhierarchy(e.g.,"Zend_Example_Class"willmap
*to"Zend/Example/Class.php").
*
*Ifthefilewasnotfoundinthe$dirs,orifno$dirswerespecified,
*itwillattempttoloaditfromPHP'sinclude_path.
*
*@paramstring$class-ThefullclassnameofaZendcomponent.
*@paramstring|array$dirs-OPTIONALEitherapathoranarrayofpaths
*tosearch.
*@returnvoid
*@throwsZend_Exception
*/
publicstaticfunctionloadClass($class,$dirs=null)
{
if(class_exists($class,false)||interface_exists($class,false)){
return;
}
if((null!==$dirs)&&!is_string($dirs)&&!is_array($dirs)){
require_once'Zend/Exception.php';
thrownewZend_Exception('Directoryargumentmustbeastringoranarray');
}
//Autodiscoverthepathfromtheclassname
//ImplementationisPHPnamespace-aware,andbasedon
//FrameworkInteropGroupreferenceimplementation:
//http://groups.google.com/group/php-standards/web/psr-0-final-proposal
$className=ltrim($class,'\\');
$file='';
$namespace='';
if($lastNsPos=strripos($className,'\\')){
$namespace=substr($className,0,$lastNsPos);
$className=substr($className,$lastNsPos+1);
$file=str_replace('\\',DIRECTORY_SEPARATOR,$namespace).DIRECTORY_SEPARATOR;
}
$file.=str_replace('_',DIRECTORY_SEPARATOR,$className).'.php';
if(!empty($dirs)){
//usetheautodiscoveredpath
$dirPath=dirname($file);
if(is_string($dirs)){
$dirs=explode(PATH_SEPARATOR,$dirs);
}
foreach($dirsas$key=>$dir){
if($dir=='.'){
$dirs[$key]=$dirPath;
}else{
$dir=rtrim($dir,'\\/');
$dirs[$key]=$dir.DIRECTORY_SEPARATOR.$dirPath;
}
}
$file=basename($file);
self::loadFile($file,$dirs,true);
}else{
self::loadFile($file,null,true);
}
if(!class_exists($class,false)&&!interface_exists($class,false)){
require_once'Zend/Exception.php';
thrownewZend_Exception("File\"$file\"doesnotexistorclass\"$class\"wasnotfoundinthefile");
}
}
$class类名将会根据下划线(作为目录分隔线)对应到相应目录下的PHP文件,并加上'.php',比如Container_Tree会指向Container\\Tree.php。
$dir 可以是数组或者字符串。目录是除去类名包含的目录的路径。
3.判断某个文件是否可读
具体使用:
if(Zend_Loader::isReadable($filename)){
//dosomethingwith$filename
}
具体实现:
/**
*ReturnsTRUEifthe$filenameisreadable,orFALSEotherwise.
*ThisfunctionusesthePHPinclude_path,wherePHP'sis_readable()
*doesnot.
*
*NotefromZF-2900:
*Ifyouusecustomerrorhandler,pleasecheckwhetherreturnvalue
*fromerror_reporting()iszeroornot.
*Atmarkoffopen()cannotsuppresswarningifthehandlerisused.
*
*@paramstring$filename
*@returnboolean
*/
publicstaticfunctionisReadable($filename)
{
if(is_readable($filename)){
//Returnearlyifthefilenameisreadablewithoutneedingthe
//include_path
returntrue;
}
if(strtoupper(substr(PHP_OS,0,3))=='WIN'
&&preg_match('/^[a-z]:/i',$filename)
){
//Ifonwindows,andpathprovidedisclearlyanabsolutepath,
//returnfalseimmediately
returnfalse;
}
foreach(self::explodeIncludePath()as$path){
if($path=='.'){
if(is_readable($filename)){
returntrue;
}
continue;
}
$file=$path.'/'.$filename;
if(is_readable($file)){
returntrue;
}
}
returnfalse;
}
具体参数:
$filename参数指定了要检查的文件名,包括路径信息。这个方法是将PHP函数»is_readable()封装而成的,is_readable()不会自动查找include_path下的文件,而Zend::isReadable()可以。
4.Autoloader
这个类的Autoloader功能已经不推荐使用了,所以不再讲述。还有其他的Autoloader,以后具体说明。
5.插件加载器
帮助文章给出的具体实例如下,可参考使用:
很多ZendFramework组件支持插件,允许通过指定类的前缀和到类的文件(不需要在include_path或不需要遵循传统命名约定的文件)的路径动态加载函数。Zend_Loader_PluginLoader提供了普通的函数来完成这个工作。
PluginLoader的基本用法遵循ZendFramework的命名约定(一个文件一个类),解析路径时,使用下划线作为路径分隔符。当决定是否加载特别的插件类,允许传递可选的类前缀来预处理。另外,路径按LIFO顺序来搜索。由于LIFO搜索和类的前缀,允许命名空间给插件,这样可以从早期注册的路径来覆盖插件。
基本用例
首先,假定下面的目录结构和类文件,并且根(toplevel)目录和库目录在include_path中:
application/
modules/
foo/
views/
helpers/
FormLabel.php
FormSubmit.php
bar/
views/
helpers/
FormSubmit.php
library/
Zend/
View/
Helper/
FormLabel.php
FormSubmit.php
FormText.php
现在,创建一个插件加载器来使各种各样的视图助手仓库可用:
<?php
$loader=newZend_Loader_PluginLoader();
$loader->addPrefixPath('Zend_View_Helper','Zend/View/Helper/')
->addPrefixPath('Foo_View_Helper','application/modules/foo/views/helpers')
->addPrefixPath('Bar_View_Helper','application/modules/bar/views/helpers');
?>
接着用类名中添加路径时定义的前缀后面的部分来加载一个给定的视图助手:
<?php
//load'FormText'helper:
$formTextClass=$loader->load('FormText');//'Zend_View_Helper_FormText';
//load'FormLabel'helper:
$formLabelClass=$loader->load('FormLabel');//'Foo_View_Helper_FormLabel'
//load'FormSubmit'helper:
$formSubmitClass=$loader->load('FormSubmit');//'Bar_View_Helper_FormSubmit'
?>
类加载后,就可以实例化了。
Note:为一个前缀注册多个路径
有时候,多个路径使用相同的前缀,Zend_Loader_PluginLoader实际上为每个给定的前缀注册一个路径数组;最后注册的被首先检查,当你使用孵化器里的组件时,这相当有用。
Note:实例化时定义路径
你可以提供给构造器一个可选的“前缀/路径”对(或“前缀/多个路径”)数组参数:
<?php $loader=newZend_Loader_PluginLoader(array( 'Zend_View_Helper'=>'Zend/View/Helper/', 'Foo_View_Helper'=>'application/modules/foo/views/helpers', 'Bar_View_Helper'=>'application/modules/bar/views/helpers' )); ?>
Zend_Loader_PluginLoader在不需要使用单态实例的情况下,也可选地允许共享插件,这是通过静态注册表来完成的,在实例化时需要注册表名作为构造器的第二个参数:
<?php //Storepluginsinstaticregistry'foobar': $loader=newZend_Loader_PluginLoader(array(),'foobar'); ?>
其它使用同名注册表来实例化PluginLoader的组件将可以访问已经加载的路径和插件。
处理插件路径
上节的例子示例如何给插件加载器添加路径,那么如何确定已经加载的路径或删除他们呢?
如果没有提供$prefix,getPaths($prefix=null)以“前缀/路径”对返回所有的路径;或者如果提供了$prefix,getPaths($prefix=null)返回为给定的前缀注册的路径。
clearPaths($prefix=null)将缺省地清除所有的已注册路径,或者如果提供了$prefix并放在堆栈里,只清除和那些和给定前缀关联的路径。
removePrefixPath($prefix,$path=null)允许有选择地清除和给定前缀相关的特定的路径。如果没有提供$path,所有的和前缀相关的路径被清除,如果提供了$path并且相应的前缀存在,只有这个相关的路径被清除。
测试插件和获取类的名字
有时候你想确定在执行一个动作之前是否插件类已经加载,isLoaded()返回插件名的状态。
PluginLoader的另一个普通用例是确定已加载类的完全合格的插件类名,getClassName()提供该功能。一般地,这个和isLoaded()联合使用:
<?php
if($loader->isLoaded('Adapter')){
$class=$loader->getClassName('Adapter');
$adapter=call_user_func(array($class,'getInstance'));
}
?>
具体插件加载器的实现可以参考Zend_Loader_PluginLoader和Zend_Loader。这里不在累述。
更多关于zend相关内容感兴趣的读者可查看本站专题:《ZendFrameWork框架入门教程》、《php优秀开发框架总结》、《Yii框架入门及常用技巧总结》、《ThinkPHP入门教程》、《php面向对象程序设计入门教程》、《php+mysql数据库操作入门教程》及《php常见数据库操作技巧汇总》
希望本文所述对大家PHP程序设计有所帮助。