为什么在 Composer 中使用 psr-4 自动加载时指定命名空间?

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

我对应该如何在 Composer 中使用 psr-4 自动加载感到有点困惑。假设我有这样的文件夹结构:

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

基本上,在项目根目录中:composer.json;包含 Router php class 的 Core 文件夹; App 文件夹包含 Models 文件夹,后者包含 User class.

路由器 class 看起来像这样:

<?php
namespace Core;

class Router {
}

而用户 class 看起来像这样:

<?php
namespace App\Models;

class User {
}

所以我可以使用 Composer psr-4 自动加载器自动加载这些 classes,我可以在 composer.json:

中执行此操作
{
    "autoload": {
        "psr-4": {
            "Core\": "Core",
            "App\Models\": "App/Models"
        }
    }
}

所以我可以像这样使用 classes 而不需要它们(在 运行 composer dump-autoload 之后):

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

没有问题。

不过,我也可以在composer.json中这样做:

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

根据文档,这是一个后备目录,其中可以是任何命名空间,相对于根目录。因此,通过在作曲家自动加载器中添加这个 "empty" 条目,我相信它说“ 从根目录开始,在任何目录中查找任何名称空间 class 中的 ” ,如果我遵循正确的文件夹命名/命名空间结构,我可以自动加载我的任何 classes。

所以我的问题是,如果后者有效且简单得多,我为什么要执行前者?是性能问题吗?还是另有原因?

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

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

理由一:性价比高。定义说对于每个需要自动加载的 class,Composer 应该查看根目录。这些 class 不仅是您包裹中的那些,还有所有其他 class。

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

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

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

你也可以把class放到src/AnyClass.php中定义

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

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

在同一个包中同时拥有 Core 命名空间和 App 命名空间让我很怀疑:为什么没有一个包分别对应这些?

通常在使用composer 时,您自己的项目只有一个文件夹。那么你只需要指定一个命名空间即可。

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

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

并将您的 composer.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;