PSR-0和PSR-4之间有什么区别?

267

最近我阅读了关于命名空间及其益处的文章。我的项目正在使用Laravel框架,我试图从类映射自动加载转移到命名空间。然而,我似乎不太理解PSR-0和PSR-4之间的实际区别。

我阅读的一些资源包括:

我的理解:

  • PSR-4不会将下划线转换为目录分隔符
  • Composer的某些特定规则导致目录结构变得复杂,进而使得PSR-0命名空间冗长,因此才出现了PSR-4

希望能有例子来解释它们之间的差异。


3
阅读 PSR0PSR4,它们阐述了每个细节。 - Sverri M. Olsen
3
http://www.sitepoint.com/battle-autoloaders-psr-0-vs-psr-4/ - deceze
4
有人应该将此内容打成答案的主旨... :) - deceze
1
在我看来,PSR 中的大部分内容都是关于他们喜欢什么,而不是什么是正确的。 - Yousha Aleayoub
5个回答

317
它们非常相似,因此有点混淆并不令人惊讶。简而言之,PSR-0具有一些向后兼容的特性,适用于PEAR风格的类名,而PSR-4放弃了这些功能,因此它仅支持命名空间代码。此外,PSR-4不强制您将整个命名空间作为目录结构,而只需要锚点后面的部分。
例如,如果您定义Acme\Foo\ 命名空间在 src/中,则在使用PSR-0时,它意味着它将在 src/Acme/Foo/Bar.php 中查找 Acme\Foo\Bar,而在PSR-4中它将在src/Bar.php中查找,从而允许使用更短的目录结构。另一方面,一些人喜欢具有完整的目录结构以清晰地看到哪个命名空间中的内容,因此您还可以说Acme\Foo\src/Acme/Foo中使用PSR-4来获得上述PSR-0行为的等效结果。
长话短说,对于新项目和大多数意图,您可以使用PSR-4,并忘记PSR-0。

19
如果你输入 Acme\Foo\ => src/,它会选择 src/Bar.php - Seldaek
非常感谢您的解释! - 尤川豪
4
PSR-4比PSR-0慢,是吗? - Nguyen Linh
3
@NguyenLinh 我不这么认为。它做的事情是一样的,但可能目录层数更少,所以它可能会更快。测量一下吧。您可以创建一个包,在PSR-0和PSR-4之间切换 - 我认为您不会看到任何差异。 - Sven

57

以下是主要区别:

1. 例如,如果您定义了Acme\Foo\ 命名空间在src/中,则:

  • 使用PSR-0意味着它将查找src/Acme/Foo/Bar.php中的Acme\Foo\Bar
  • 而在PSR-4中,它将在src/Bar.php(其中Bar类位于)中查找Acme\Foo\Bar

2. PSR-4不会将下划线转换为目录分隔符

3. 您可能更喜欢使用带有命名空间的PSR-4

4. 即使类名与文件名不同,例如上面的示例,PSR-0也无法工作:

  • 对于Acme\Foo\Bar ---> src/Acme/Foo/Bar.php(用于Bar类)将起作用
  • 对于Acme\Foo\Bar ---> src/Acme/Foo/Bar2.php(用于Bar类)将不起作用

1
你肯定可以在没有命名空间的脚本中使用PSR-4,没有这样的限制,我也使用它(不是我的选择)。 - Galvani
在你的第一点中,PSR-4案例中的Bar是从哪里来的? - cjmling

42

PSR-4类似于“相对路径”,而PSR-0则是“绝对路径”。

例如:

config:

'App\Controller' => 'dir/'

PSR-0 自动加载:

App\Controller\IndexController --> dir/App/Controller/IndexController.php

PSR-4自动加载:

App\Controller\IndexController --> dir/IndexController.php

PSR-0和PSR-4之间还有一些细节上的不同,请在这里查看:http://www.php-fig.org/psr/psr-4/


33

命名空间/文件夹惯例。

类应该按照它们的命名空间存储在文件夹中。

通常,您会在根文件夹中创建一个src/目录,与vendor/处于同一级别,并将项目添加到其中。以下是文件夹结构示例:

.
+-- src
    |
    +-- Book 
    |   +-- History
    |   |   +-- UnitedStates.php - namespace Book\History;
    +-- Vehicle
    |   +-- Air
    |   |   +-- Wings
    |   |   |   +-- Airplane.php - namespace Vehicle\Air\Wings;
    |   +-- Road
    |   |   +-- Car.php - namespace Vehicle\Road;
+-- tests
    +-- test.php
+-- vendor

psr-0和psr-4的区别

psr-0

该标准已经被弃用。查看vendor/composer/autoload_namespaces.php文件,您可以看到命名空间及其映射到的目录。

composer.json

"autoload": {
        "psr-0": {
            "Book\\": "src/",
            "Vehicle\\": "src/"
        }
} 
  • src/Book/History/UnitedStates.php 中查找 Book\History\UnitedStates 的内容。
  • src/Vehicle/Air/Wings/Airplane.php 中查找 Vehicle\Air\Wings\Airplane 的内容。

psr-4

查看 vendor/composer/autoload_psr4.php 文件,可以看到命名空间和它们映射到的目录。

composer.json

"autoload": {
    "psr-4": {
        "Book\\": "src/",
        "Vehicle\\": "src/"
    }
}   
  • src/History/UnitedStates.php 中查找图书历史\美国
  • src/Air/Wings/Airplane.php 中查找车辆\空中\机翼\飞机

composer.json

"autoload": {
    "psr-4": {
        "Book\\": "src/Book/",
        "Vehicle\\": "src/Vehicle/"
    }
}    
  • 寻找 Book\History\UnitedStates, 位于 src/Book/History/UnitedStates.php
  • 寻找 Vehicle\Air\Wings\Airplane, 位于 src/Vehicle/Air/Wings/Airplane.php

2
在这个问题上我挣扎了一段时间,直到看到了这篇文章。非常感谢您提供简洁明了的示例! - Ricky Goldman

-7

即使我尝试过,但Composer仍然很混乱。可悲的是,这是市场上唯一的选择。
为什么会这样呢?
如果您控制代码,则Composer的自动完成功能正常运行。但是,如果您导入不同的项目,则会发现有许多样式和创建文件夹的方法。例如,某些项目是/company/src/class.php,而其他项目是company/class.php,还有其他项目是company/src/class/class.php

我创建了一个解决方案库:

https://github.com/EFTEC/AutoLoadOne(它是免费的,MIT许可证)。

它通过扫描文件夹中的所有类来生成自动包含,因此在每种情况下都可以使用(psr-0 psr-4,没有命名空间的类,具有多个类的文件等)。

编辑:再次被投票否决,没有任何理由。;-)


1
了解一下composer.json中的classmap选项。https://getcomposer.org/doc/04-schema.md#classmap - 这可能是你的答案被踩的原因。 - Patrick
@Patrick,我看了他的库。这是一个有趣的方法。我的意思是,对于我来说,仅仅为了避免composer的classmaps而使用它有点过了,但还好。 - Lawrence

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接