我看到了很多使用PSR进行命名空间自动加载的例子。也许这是一个愚蠢的问题,但为什么这不是一个糟糕的做法?这难道不违背拥有名称空间的目的吗?
例如,假设您有两个库,FormBuilder
和MySweetForms
,并且都有一个Form
类。地点位于:
lib/FormBuilder/Core/Form.php
和lib/MySweetForms/Form.php
如果您根据Form
类所在的名称空间进行自动加载,难道不会遇到名称空间旨在防止的确切问题:类和方法的标识符不明确吗?
当您成功地在MySweetForms
命名空间中找到另一个依赖于'MySweetForms'Form
的类,比如AjaxFileField
,但它找到了FormBuilder
对Form
类的实现时,它不会失败吗?
由于名称空间的原因,如果自动加载程序和两个库遵循最佳(或接近最佳)实践并正确实现,则在寻找MySweetForms
实现时,自动加载不会找到FormBuilder
对Form
类的实现。
如果MySweetForms/AjaxFileField.php
文件在MySweetForms
名称空间内定义了一个类,如图所示:
namespace MySweetForms;
class AjaxFileField
{
public function doFormStuff()
{
$form = new Form();
}
}
那么,在AjaxFileField
内部对Form
类的引用对于完全限定类名MySweetForms'Form
来说实际上是一个捷径。
当调用自动加载器来加载类时,它将被要求根据类的完全限定名称来加载类。PSR-0自动加载器会将MySweetForms'Form
类名转换为MySweetForms/Form.php
路径,并且(如果告诉它在lib
目录中查找)它会找到正确的文件。如果该文件丢失,自动加载器最终会失败。类似地,如果该文件定义了Form
类,但忽略了提供命名空间,则实际类(MySweetForms'Form
)将不存在(相反,全局类Form
将不存在)——这与AjaxFileField
类中引用的类的完全限定名称不匹配,因此会发生错误。
请注意,如果代码中包含$form = new 'FormBuilder'Core'Form();
,那么类名将已经完全限定,并且自动加载器将被要求加载FormBuilder'Core'Form
类(并且希望它在FormBuilder/Core/Form.php
文件中)。
如果我们使用了$form = new 'Form();
,我们将引用全局命名空间中的Form
类,并且自动加载器将被要求查找Form
(此时它将直接在lib
文件夹内的Form.php
文件中查找)。
关键是要认识到,实际上并没有两个Form
类——一个类的完全限定名为FormBuilder'Core'Form
,另一个类为MySweetForms'Form
——而一个正确实现的自动加载器会将它们放在完全不同的位置,并且不会试图加载一个文件来代替另一个文件。
名称空间和基于名称空间将文件组织到目录中的PSR风格的结合,使重用常用词变得非常容易,而不会引起冲突,并可预测地将完全限定的类名映射到相应的文件。
将类名解析为完全限定类名是实现这一点的关键,PHP手册中对此进行了讨论(命名空间常见问题解答有几点:http://www.php.net/manual/en/language.namespaces.faq.php)。PSR-0标准本身也是一个有用的参考:https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md