目录
介绍
目标与设计
自动加载的基本用法
资源的自动加载
结论
介绍
自动加载是一种机制,这种机制可以在你的PHP代码中无需手动设置依赖的文件。每一个 » the PHP 自动加载手册中都强调,一旦自动加载器被定义,它“在你试图使用一个还没被定义的类或接口,将被自动调用”
使用自动加载,你无需担心一个类在你的项目中的什么地方。使用良好定义的自动加载,你无需担心一个类文件相对于当前类文件的什么位置;你只要简单的使用这个类,自动加载器将会执行文件查找任务。
另外,自动加载,因为它直到最后一刻才载入并确信匹配只出现一次,是一次巨大的性能提升——特别是在你部署之前如果花时间清除require_once()调用的时候
Zend Framework鼓励使用自动加载,并提供许多工具提供库代码和应用程序代码的自动加载。这个教程覆盖了这些工具,也告诉你如何高效的使用它们。
目标与设计
类的命名约定
为了明白Zend Framework中的自动加载,首先你需要明白类名和类文件的关系。
Zend Framework从PEAR中借鉴了一个思想,即类名和文件系统是一个1:1的关系。为了解决文件路径,简单的将下划线”_”替换为目录分隔符,然后加上后缀“.php”。比如,“Foo_Bar_Baz”将对应文件系统中的"Foo/Bar/Baz.php"。假设该类也可以通过PHP的include_path设置来解决,它允许include()和require()在include_path中通过相对路径寻找文件名
另外,每一个PEAR及PHP 项目,我们使用并推荐为你的代码使用供应商(vendor)或者项目前缀。这意味着你写的所有类将分享同一个类前缀;比如,在Zend Framework 中的所有代码有“Zend_”前缀。这个命名约定帮助防止命名冲突。在Zend Framework中,我们经常称之为“命名空间”前缀;注意不要把它与PHP的本地命名空间混淆(be careful not to confuse it with PHP's native namespace implementation)。
Zend Framework在内部遵循这些简单的规则。我们的代码标准鼓励你这样做,就像对所有的库代码一样。
自动加载器的协定和设计
Zend Framework的自动加载支持,首先由Zend_Loader_Autoloader提供,有下面的目标和设计元素:
· 提供命名空间匹配。如果类的命名空间前缀不在注册的命名空间列表中,则立即返回FALSE。这样就可以比较乐观的匹配,就像会退到其他的自动加载器(This allows for more optimistic matching, as well as fallback to other autoloaders.)
· 允许自动加载器作为一个备份的自动加载器。在一个团队可能分布很广泛,或者使用一个未确定的命名空间前缀设置的情况下,自动加载器应该仍然被设置的以便它试图去匹配任何命名空间前缀。注意,这种做法是不推荐的,因为它会导致不必要的查找
· 允许触发错误抑制。我们感觉到——伟大的PHP社区也是这样的——错误抑制是一个坏主意。它昂贵并且覆盖非常真实的应用程序问题。所以,默认情况下,它应该是关的。然而,如果开发者坚持打开它,我们也允许这么做。
· 允许指定为自动加载自定义回调。一些开发者不想去使用Zend_Loader::loadClass()去自动加载,但是仍然想去使用Zend Framework的机制。Zend_Loader_Autoloader允许为自动加载指定一个候选的回调
· 允许操作SPL自动加载链。这样做的目的是允许指定另外的自动加载器——比如,类的资源加载器没有与文件系统有1:1的映射关系——在主Zend Framework自动加载器之前或之后被注册
自动加载器的基本用法
既然我们已经懂得了什么是自动加载,并懂得了 Framework自动加载解决办法的目标和设计。下面让我们开看看怎么去使用Zend_Loader_Autoloader。
在最简单的情况下,你只需要require这个类,然后实例化它,因为Zend_Loader_Autoloader是一个单态(singleton)的(因为SPL自动加载器是一个单个资源的原因),我们使用getInstance()去获取一个实例。
require_once 'Zend/Loader/Autoloader.php';
Zend_Loader_Autoloader::getInstance();
默认情况下,这将允许你载入任何带有"Zend_" 或者 "ZendX_"的类命名空间前缀的类,只要它们在你的include_path里
如果你有其他的命名空间前缀要去使用会发生什么?最好的、最简单的方法是在实例上调用registerNamespace()方法
require_once 'Zend/Loader/Autoloader.php';
$loader = Zend_Loader_Autoloader::getInstance();
$loader->registerNamespace('Foo_');
$loader->registerNamespace(array('Foo_', 'Bar_'));
或者,你可以告诉Zend_Loader_Autoloader去担当一个“后备(fallback)”自动加载器。这意味着它将不管命名空间前缀都将去处理任何类。
$loader->setFallbackAutoloader(true);
警告
不要使用后备(fallback)自动加载器
当试图去使用Zend_Loader_Autoloader作为后备自动加载器时,我们不推荐这样做。
内部的,Zend_Loader_Autoloader 使用 Zend_Loader::loadClass()来导入类。那个方法使用include()试图导入给定的类文件,如果不成功include()将返回一个布尔量FALSE,而且发布一个PHP警告。后者实际上可能会导致一些问题:
如果display_errors是启用的,警告将包含在输出中
一来你已经选择的error_reporting级别,它可能也会弄乱你的日志
你能够压制错误信息(Zend_Loader_Autoloader文档详细介绍这个),但是注意当display_errors是启用的,压制仅仅是相关的;错误日志将也会总是显示消息。因为这些原因,我们推荐总是设置能被自动加载器意识到的命名空间前缀
注: 命名空间前缀vs PHP 命名空间
在写这个教程的时候,PHP5.3已经发布了,在这个版本下,PHP现在已经官方支持命名空间了。
然而,Zend Framework在日期上早于PHP5.3建立,命名空间同样也是这样。在Zend Framework中,我们指的“命名空间”是实践上的命名空间,即带有厂商(vendor)“命名空间”为前缀的类。举例来说,所有的Zend Framework类名称都以“Zend_”为前缀——那就是我们的厂商(vendor)“命名空间”
Zend Framework计划在将来版本中的自动加载器中提供本地PHP命名空间支持。并且,它的自己的library将在2.0.0版本中使用命名空间
如果你有一个希望使用Zend Frameworkd 自定义的自动加载器——也许你也使用一个第三方库中的自动加载器——你可以使用Zend_Loader_Autoloader的pushAutoloader()和unshiftAutoloader()方法来管理。这些方法将相应的在后面或前面面(append or prepend)添加自动加载器到一个被称为前执行Zend Framework的内部自动载入机制链(These methods will append or prepend, respectively, autoloaders to a chain that is called prior to executing Zend Framework's internal autoloading mechanism)。这种方法具有以下优点:
每种方法接受可选的第二个参数:类命名空间前缀。这可以用来指示给定的自动加载器应该仅仅在寻找带有指定类前缀的类时被使用。如果处理的类没有那个前缀,自动加载器将被跳过——这将导致性能改进
如果你需要操作spl_autoload()的注册表,任何自动加载器即指向实例方法的回调可能会造成问题(any autoloaders that are callbacks pointing to instance methods can pose issues),因为spl_autoload_functions()不返回确切的同样回调。Zend_Loader_Autoloader没有那样的限制。
管理这种方式的自动加载器可以使任何有效的PHP回调(Autoloaders managed this way may be any valid PHP callback)。
// Append function 'my_autoloader' to the stack,
// to manage classes with the prefix 'My_':
$loader->pushAutoloader('my_autoloader', 'My_');
// Prepend static method Foo_Loader::autoload() to the stack,
// to manage classes with the prefix 'Foo_':
$loader->unshiftAutoloader(array('Foo_Loader', 'autoload'), 'Foo_');
资源自动加载
如果你通读autoloader的设计目标,在那节的最后一点指出解决方法应包括这个情况。Zend Framework用Zend_Loader_Autoloader_Resource做这些事情
资源仅仅是一个对应组件命名空间(其加在自动加载器命名空间之后)的名字和路径(其是相对于自动加载器基路径)。在动作中,我们将象下面这样做:
$loader = new Zend_Application_Module_Autoloader(array(
'namespace' => 'Blog',
'basePath' => APPLICATION_PATH . '/modules/blog',
));
一旦你在合适的位置有了加载器,你就需要将许多的它知道的资源类型通知它(you then need to inform it of the various resource types it's aware of)。这些资源类型是简单的子树(subtree)和前缀的配对
举例来说,考虑一下下面的树
path/to/some/resources/
|-- forms/
| `-- Guestbook.php // Foo_Form_Guestbook
|-- models/
| |-- DbTable/
| | `-- Guestbook.php // Foo_Model_DbTable_Guestbook
| |-- Guestbook.php // Foo_Model_Guestbook
| `-- GuestbookMapper.php // Foo_Model_GuestbookMapper
我们第一步是创建资源加载器:
$loader = new Zend_Loader_Autoloader_Resource(array(
'basePath' => 'path/to/some/resources/',
'namespace' => 'Foo',
));
下一步,我们需要去定义一些资源类型。
Zend_Loader_Autoloader_Resourse::addResourceType()有三个参数:资源“类型”(任意字符串)、基路径下的可能存在资源类型的路径和为资源类型使用的组件前缀。在上面的树中,我们有三个资源类型:表单(在 “forms” 子目录中,带有一个组件前缀“Form”)、模型(在“models”子目录中,带有一个组件前缀“Model”)和dbtable(在“models/DbTable”子目录中,带有“Model_DbTable”组件前缀)。我们像下面这样定义它们
$loader->addResourceType('form', 'forms', 'Form')
->addResourceType('model', 'models', 'Model')
->addResourceType('dbtable', 'models/DbTable', 'Model_DbTable');
一旦定义了,我们能够简单的使用下面的类
$form = new Foo_Form_Guestbook();
$guestbook = new Foo_Model_Guestbook();
注:模块(module)资源的自动加载
Zend Framework 的MVC层鼓励使用“模块(modules)”,它是在你的站点中自包含的应用程序。默认情况下模块典型的有许多资源类型,Zend Framework甚至为模块推荐一个标准的目录布局。资源自动载入器因此在这个范例中是非常有用的——那么的有用以至于,当你为你的模块(module)创建扩展于Zend_Application_Module_Bootstrap的一个引导类(bootstrap class)时,默认情况下它们是启用的。更多的信息请参考Zend_Loader_Autoloader_Module 文档。
结论
Zend Framework鼓励使用autoloading,甚至在Zend_Application中默认初始化它。希望这个教程最大程度的提供给你需要使用的Zend_Loader_Autoloader的信息以及通过附加自定义的自动加载器或者资源自动加载器来扩展它的功能。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/dxcjpu/archive/2010/05/11/5578581.aspx