我对如何在作曲家中使用 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 AppModels;
class User {
}
所以我可以使用作曲家 psr-4 自动加载器自动加载这些类,我可以在 composer.json 中执行此操作:
{
"autoload": {
"psr-4": {
"Core\": "Core",
"App\Models\": "App/Models"
}
}
}
所以我可以在不需要它们的情况下使用这些类(在运行 composer dump-autoload
之后),如下所示:
$router = new CoreRouter();
$user = new AppModelsUser();
这没有问题。
但是,我也可以在 composer.json 中执行此操作:
{
"autoload": {
"psr-4": {
"": ""
}
}
}
根据文档,这是一个回退目录,任何命名空间都可以相对于根目录。因此,通过在作曲家自动加载器中拥有这个"空"条目,我相信它说"从根目录开始,在任何目录中查找任何命名空间中的类",如果我遵循正确的文件夹命名/命名空间结构,我可以自动加载我的任何类。
所以我的问题是,如果后者有效并且更简单,我为什么要做前者?是性能问题吗?还是有其他原因?
为什么你不应该总是做"psr-4": {"": ""}
?
原因一:性价比高。该定义说,对于每个需要自动加载的类,Composer 应该查看根目录。这些类不仅是包中的类,也是所有其他类。
Composer 试图通过记住无果的搜索来稍微优化这项工作,但这只有在您加载具有相同前缀的另一个类时才值得。
原因 2:PSR-4 的本质是不必将整个命名空间路径映射到目录路径。假设你有一个处理一组非常特定的类的包,如VendorTemplateEscapingOutput*
,没有别的(拥有小包可以更容易地重用它们而无需添加太多代码),你可以将它们放在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 MyAppCoreRouter;
$user = new MyAppAppModelsUser;
或者像这样:
namespace MyApp;
$router = new CoreRouter;
$user = new AppModelsUser;
PSR-4 是将命名空间转换为物理目录的标准。