2

我已经看到一堆使用 PSR 进行命名空间自动加载的示例。也许这是一个愚蠢的问题,但为什么这不是不好的做法?这不会违背拥有命名空间的目的吗?

例如,假设您有两个库,FormBuilder并且MySweetForms, 并且都有一个Form类。地点在:

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

如果您根据这些Form类所在的命名空间自动加载,您是否会遇到命名空间旨在防止的确切问题:类和方法的模棱两可的标识符?

当您在命名空间中成功找到另一个类时,它不会失败MySweetForms,例如AjaxFileField,它依赖于\MySweetForms\Form,但它找到FormBuilder了该类的实现Form

4

1 回答 1

0

FormBuilder由于命名空间,自动加载在寻找实现时不会找到Form类的MySweetForms实现,前提是自动加载器和两个库遵循最佳(或接近最佳)实践并正确实现。

如果MySweetForms/AjaxFileField.php文件在命名空间内定义了一个类,MySweetForms如下所示:

namespace MySweetForms;

class AjaxFileField
{
    public function doFormStuff()
    {
        $form = new Form();
    }
}

那么Form里面类的引用AjaxFileField其实就是全限定类名的简写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(此时它将Form.php直接在lib文件夹内的文件中查找)。

关键是要认识到实际上并没有两个Form类——一个类的完全限定名是FormBuilder\Core\Form,一个类的完全限定名是MySweetForms\Form——并且正确实施的自动加载器会期望它们位于完全不同的位置,不会尝试加载一个文件来代替另一个文件。

命名空间和基于命名空间将文件组织到目录中的 PSR 风格相结合,使得在不引起冲突的情况下重用常用词变得非常容易,并将完全限定的类名可预测地映射到相应的文件。

将类名解析为完全限定的类名是这一点的关键,并在 PHP 手册中进行了讨论(命名空间常见问题解答有几点关于它:http://www.php.net/manual/en/language。命名空间.faq.php)。PSR-0 标准本身也是一个有用的参考:https ://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md

于 2013-06-26T03:40:18.427 回答