为什么';t使用命名空间自动加载不良做法


Why Isn't Using Namespaces for Autoloading Bad Practice?

我看到了很多使用PSR进行命名空间自动加载的例子。也许这是一个愚蠢的问题,但为什么这不是一个糟糕的做法?这难道不违背拥有名称空间的目的吗?

例如,假设您有两个库,FormBuilderMySweetForms,并且都有一个Form类。地点位于:

lib/FormBuilder/Core/Form.phplib/MySweetForms/Form.php

如果您根据Form类所在的名称空间进行自动加载,难道不会遇到名称空间旨在防止的确切问题:类和方法的标识符不明确吗?

当您成功地在MySweetForms命名空间中找到另一个依赖于'MySweetForms'Form的类,比如AjaxFileField,但它找到了FormBuilderForm类的实现时,它不会失败吗?

由于名称空间的原因,如果自动加载程序和两个库遵循最佳(或接近最佳)实践并正确实现,则在寻找MySweetForms实现时,自动加载不会找到FormBuilderForm类的实现。

如果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