为什么在将 psr-4 自动加载与作赞器一起使用时指定命名空间


Why specify the namespace when using psr-4 autoloading with Composer?

我对如何在作曲家中使用 psr-4 自动加载有点困惑。假设我有一个这样的文件夹结构:

/
|- Core/
|   - Router.php
|- App/
|   - Models
|       User.php
|- composer.json

基本上,在项目根目录中:composer.json;一个包含Router php类的核心文件夹;一个包含包含User类的Models文件夹的App文件夹。

路由器类如下所示:

<?php
namespace Core;
class Router {
}

用户类如下所示:

<?php
namespace App'Models;
class User {
}

所以我可以使用作曲家 psr-4 自动加载器自动加载这些类,我可以在 composer.json 中执行此操作:

{
    "autoload": {
        "psr-4": {
            "Core''": "Core",
            "App''Models''": "App/Models"
        }
    }
}

所以我可以在不需要它们的情况下使用这些类(在运行 composer dump-autoload 之后),如下所示:

$router = new Core'Router();
$user = new App'Models'User();

这没有问题。

但是,我也可以在 composer.json 中执行此操作:

{
    "autoload": {
        "psr-4": {
            "": ""
        }
    }
}

根据文档,这是一个回退目录,任何命名空间都可以相对于根目录。因此,通过在作曲家自动加载器中拥有这个"空"条目,我相信它说"从根目录开始,在任何目录中查找任何命名空间中的类",如果我遵循正确的文件夹命名/命名空间结构,我可以自动加载我的任何类。

所以我的问题是,如果后者有效并且更简单,我为什么要做前者?是性能问题吗?还是有其他原因?

为什么你不应该总是做"psr-4": {"": ""}

原因一:性价比高。该定义说,对于每个需要自动加载的类,Composer 应该查看根目录。这些类不仅是包中的类,也是所有其他类。

Composer 试图通过记住无果的搜索来稍微优化这项工作,但这只有在您加载具有相同前缀的另一个类时才值得。

原因 2:PSR-4 的本质是不必将整个命名空间路径映射到目录路径。假设你有一个处理一组非常特定的类的包,如'Vendor'Template'Escaping'Output'*,没有别的(拥有小包可以更容易地重用它们而无需添加太多代码),你可以将它们放在src/Vendor/Template/Escaping/Output/AnyClass.php中并定义

"psr-4": {
        "''Vendor''Template''Escaping''Output''": "src/Vendor/Template/Escaping/Output/"
}

您还可以将类放入src/AnyClass.php并定义

"psr-4": {
        "''Vendor''Template''Escaping''Output''": "src/"
}

这大大缩短了目录路径,略微提高了速度(我认为 - 虽然没有数字),但由于空文件夹的打开次数减少,主要改善了开发。

在同一个包中同时具有 Core 命名空间和 App 命名空间让我怀疑:为什么每个包都不是一个包?

使用作曲家时,通常只有一个文件夹用于自己的项目。然后,只需指定一个命名空间。

考虑将文件结构重新排列为

/
|- lib/
|   - Core/
|      - Router.php
|   - App/
|      - Models
|          User.php
|- composer.json

并将您的作曲家.json 更改为

{
    "autoload": {
        "psr-4": {
            "MyApp''": "lib/"
        }
    }
}

然后,您只有一个指定的命名空间,无需添加任何其他命名空间。您可以像这样调用您的类:

$router = new 'MyApp'Core'Router;
$user   = new 'MyApp'App'Models'User;

或者像这样:

namespace MyApp;
$router = new Core'Router;
$user   = new App'Models'User;

PSR-4 是将命名空间转换为物理目录的标准。