目录
- 介绍
- 使用插件
- 结论
介绍
Zend Framework大量使用插件架构。插件考虑到当保持你的代码与Zend Framework代码分离时易于扩展和框架的定制。
典型地,Zend Framework中的插件像下面这样工作:
· 插件是类。实际的类定义将基于组件而有所不同——你可能需要扩展一个抽象类(extend an abstract)或者实现一个接口(implement an interface),但事实上,这个插件本身是一个类。
· 相关的插件将分享一个共同的类前缀。比如,如果你已经创建了一些视图助手(view helpers),他们可能都分享同样的“Foo_View_helper_”类前缀。
· 在共同的前缀后的任何东西将被认为是插件名或者短(short)名称(相对于长名称(long name),它指完整的类名)。比如,如果插件前缀是“Foo_View_Helper_”,类名是"Foo_View_Helper_Bar",插件名将是简单的“Bar”。
· 插件名通常是区分大小写的。一个需要注意的是,初始的字母常是小写或是大写的;在我们前面的例子中,“bar”和“Bar”将指向同一个插件。
现在,轮到我们使用插件了。
使用插件
使用插件的组件通常使用Zend_Loader_PluginLoader去完成工作。这个类有你通过指定一个或更多的“前缀路径”注册的插件。然后组件将调用PluginLoader的 load()方法,传递该插件的短名字给它。接着PluginLoader将查询每一个前缀路径去看看是否存在一个匹配那个短名字的类。前缀路径将通过LIFO顺序(后进先出)被搜索。所以它将后进先出的匹配那些注册的前缀路径——允许你去覆盖已经存在的插件。
示例 #1 基本插件示例:增加一个单前缀路径
在这个例子中,我们将假设已经有了一些校验器并且放置在目录foo/plugins/validators/中,所有的这些类分享共同的类前缀“Foo_Validate_”;这些两位的信息建立了我们的“前缀路径”。而且假设我们有两个校验器,一个名为“Even”(确保将被校验的数字式一个偶数),另外一个名为“Dozens”(确保数字式12的倍数)。目录树看起来像下面这样:
- foo/
- |-- plugins/
- | |-- validators/
- | | |-- Even.php
- | | |-- Dozens.php
现在,我们将告诉你一个以这个为前缀路径的Zend_Form_Element实例。Zend_Form_Element的 addPrefixPath() 方法期待第三个参数,该参数表明路径正在被注册的插件的类型,在这个例子中,它是一个“校验”插件。(Now, we'll inform a Zend_Form_Element instance of this prefix path. Zend_Form_Element's addPrefixPath() method expects a third argument that indicates the type of plugin for which the path is being registered; in this case, it's a "validate" plugin.)
- $element->addPrefixPath('Foo_Validate', 'foo/plugins/validators/', 'validate');
现在我们能简单的告诉这个元素我们想使用的校验器的短名称。在下面的例子中,我们正使用一种标准校验器("NotEmpty", "Int")和自定义校验器("Even", "Dozens")的混合:
- $element->addValidator('NotEmpty')
- ->addValidator('Int')
- ->addValidator('Even')
- ->addValidator('Dozens');
当元素需要去校验,它将从插件装载器(PluginLoader)中请求插件。前两个校验器将相应的解析为Zend_Validate_NotEmpty and Zend_Validate_Int,后两个将相应的解析为Foo_Validate_Even and Foo_Validate_Dozens
注:如果没有找到插件将会发生什么
如果一个插件被请求,但是插件装载器(PluginLoader)不能够找了匹配的类将发生什么?比如,在上个例子中,如果我们用这个元素注册插件“Bar”,什么将发生?插件加载器将浏览每一个前缀路径,检查在那个路径上能否找到一个文件匹配插件的名称。如果找不到,将移动到下一个前缀路径进行搜索。一旦穷尽插件路径的堆栈,还没有找到匹配的文件,它将抛出一个Zend_Loader_PluginLoader_Exception异常。
示例 #2 中间插件的使用: 重写现有插件
插件加载器(PluginLoader)的一个长处是它LIFO堆栈的使用允许你通过创建你自己的带有不同前缀路径的本地版本去重写现有堆栈,并晚一点在堆栈中注册那个前缀路径
比如,我们来考虑下Zend_View_Helper_FormButton(视图助手是插件的一种形式)。这个视图助手接受三个参数,元素名(也被用作为元素的DOM标识符)、值(用作按钮标签)和一个可选的属性数组。这个助手然后为表单输出元素产生HTML标签
我们说你要的助手而不是产生一个真正的HTML按钮元素(Let's say you want the helper to instead generate a true HTML button element;);不要想让这个助手去产生一个DOM标识符,而是使用一个CSS类选择器的值;而且你没有兴趣处理任何属性。你可以用两种方法完成这个。在这两种方法中,你创建你自己的视图助手类实现你想要的行为;所不同的就是你将如何命名和调用它们。
我们的第一个例子将使用唯一的名称命名这个元素:Foo_View_Helper_CssButton,它隐含着插件名“CssButton”。虽然这无疑是一个可行的办法,但是它提出了几个问题:如果在代码中你已经使用按钮(Button)视图助手,你现在必须重构(refactor);或者,如果另外的开发者开始为你的应用程序写代码,它们可能无意中使用Button视图助手而不是用你的新视图助手
所以,较好的例子是去使用插件名“Button”,相应的类名就是Foo_View_Helper_Button。我们然后将用这个视图注册前缀路径:
- // Zend_View::addHelperPath() utilizes the PluginLoader; however, it inverts
- // the arguments, as it provides a default value of "Zend_View_Helper" for the
- // plugin prefix.
- //
- // The below assumes your class is in the directory 'foo/view/helpers/'.
- $view->addHelperPath('foo/view/helpers', 'Foo_View_Helper');
一旦这么做了,无论在什么地方,你现在使用的“Button”视图将委托给你的自定义的Foo_View_Helper_Button类!
结论
明白前缀路径的概念和重写已有的插件将帮助你明白框架中的许多组件、插件被用在各种地方:
· Zend_Application: resources.
· Zend_Controller_Action: action helpers.
· Zend_Feed_Reader: plugins.
· Zend_Form: elements, filters, validators, and decorators.
· Zend_View: view helpers.
而且还有几个地方使用。早点地学习这个概念你能够利用这个在Zend Framework中重要的延伸点
注: 警告
我们这儿注意一下Zend_Controller_Front有的一个插件系统——但是它不坚持这个教程里的任何准则。用前端控制器注册的插件必须直接被实例化并且用它单独注册。原因是这个系统在框架中早于任何其他的插件系统,并且它的变化必须仔细权衡以确保现有的开发者写的插件继续与它一起工作。