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

Php 为什么在使用psr-4自动加载Composer时指定名称空间?,php,namespaces,composer-php,autoload,psr-4,Php,Namespaces,Composer Php,Autoload,Psr 4,我对如何在Composer中使用psr-4自动加载有点困惑。假设我有一个这样的文件夹结构: / |- Core/ | - Router.php |- App/ | - Models | User.php |- composer.json <?php namespace Core; class Router { } <?php namespace App\Models; class User { } $router = new Core\Router();

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

/
|- Core/
|   - Router.php
|- App/
|   - Models
|       User.php
|- composer.json
<?php
namespace Core;

class Router {
}
<?php
namespace App\Models;

class User {
}
$router = new Core\Router();
$user = new App\Models\User();
$router = new \MyApp\Core\Router;
$user   = new \MyApp\App\Models\User;
namespace MyApp;
$router = new Core\Router;
$user   = new App\Models\User;
基本上,在项目根目录中:composer.json;一个核心文件夹,包含一个路由器php类;一个应用程序文件夹,其中包含一个模型文件夹,该文件夹包含一个用户

路由器类如下所示:

/
|- Core/
|   - Router.php
|- App/
|   - Models
|       User.php
|- composer.json
<?php
namespace Core;

class Router {
}
<?php
namespace App\Models;

class User {
}
$router = new Core\Router();
$user = new App\Models\User();
$router = new \MyApp\Core\Router;
$user   = new \MyApp\App\Models\User;
namespace MyApp;
$router = new Core\Router;
$user   = new App\Models\User;
因此,我可以使用这些类而不需要它们(在运行
composer dump autoload
之后),如下所示:

/
|- Core/
|   - Router.php
|- App/
|   - Models
|       User.php
|- composer.json
<?php
namespace Core;

class Router {
}
<?php
namespace App\Models;

class User {
}
$router = new Core\Router();
$user = new App\Models\User();
$router = new \MyApp\Core\Router;
$user   = new \MyApp\App\Models\User;
namespace MyApp;
$router = new Core\Router;
$user   = new App\Models\User;
这样做没有问题

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

{
    "autoload": {
        "psr-4": {
            "Core\\": "Core",
            "App\\Models\\": "App/Models"
        }
    }
}
{
    "autoload": {
        "psr-4": {
            "": ""
        }
    }
}
根据文档,它是一个回退目录,相对于根,任何名称空间都可以在其中。因此,通过在composer autoloader中设置这个“空”条目,我相信它会说“从根目录开始,在任何目录中查找任何命名空间中的类”,如果遵循正确的文件夹命名/命名空间结构,我可以自动加载我的任何类


所以我的问题是,如果后者有效且简单得多,我为什么要做前者?这是表演吗?或者还有其他原因吗?

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

为什么不总是执行
“PSR-4”:{“:”}

理由1:它具有成本效益。定义说,对于每个需要自动加载的类,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/"
}
"psr-4": {
        "\\Vendor\\Template\\Escaping\\Output\\": "src/"
}
您还可以将该类放入
src/AnyClass.php
并定义

"psr-4": {
        "\\Vendor\\Template\\Escaping\\Output\\": "src/Vendor/Template/Escaping/Output/"
}
"psr-4": {
        "\\Vendor\\Template\\Escaping\\Output\\": "src/"
}
这大大缩短了目录路径,略微提高了速度(我想-虽然没有数字),但由于减少了打开空文件夹的次数,主要是改进了开发过程


在同一个包中同时包含
核心
命名空间和
应用程序
命名空间,这让我怀疑:为什么没有一个包来存放这些命名空间?

通常在使用composer时,您自己的项目只有一个文件夹。然后只需要指定一个名称空间

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

/
|- lib/
|   - Core/
|      - Router.php
|   - App/
|      - Models
|          User.php
|- composer.json
并将composer.json更改为

{
    "autoload": {
        "psr-4": {
            "MyApp\\": "lib/"
        }
    }
}
然后您只有一个指定的名称空间,不需要再添加任何名称空间。您可以这样调用您的类:

/
|- Core/
|   - Router.php
|- App/
|   - Models
|       User.php
|- composer.json
<?php
namespace Core;

class Router {
}
<?php
namespace App\Models;

class User {
}
$router = new Core\Router();
$user = new App\Models\User();
$router = new \MyApp\Core\Router;
$user   = new \MyApp\App\Models\User;
namespace MyApp;
$router = new Core\Router;
$user   = new App\Models\User;
或者像这样:

/
|- Core/
|   - Router.php
|- App/
|   - Models
|       User.php
|- composer.json
<?php
namespace Core;

class Router {
}
<?php
namespace App\Models;

class User {
}
$router = new Core\Router();
$user = new App\Models\User();
$router = new \MyApp\Core\Router;
$user   = new \MyApp\App\Models\User;
namespace MyApp;
$router = new Core\Router;
$user   = new App\Models\User;

我不知道。。。你为什么要这么做?我不会的。为什么你认为你应该这样做?首先,如果有一天你决定将所有模型移到其他地方,使用前一种方法你只需更改一行,使用后一种方法你将需要重命名所有的名称空间。如果你在custom/library/src中有一个自定义包,那么你可能不想使用
custom\library\src
,但是只要
。这一切都可以归结为项目中的约定,而不是apokyrfos提出的观点。@deceze-我会这么做,因为它很有效而且很简单。我想知道是否有我不应该这样做的原因(下面已经回答了)。很好的观点@apokryfos和Devon,谢谢!很好的解释,谢谢。我错误地认为psr-4必须有匹配的文件夹和名称空间。至于核心和应用程序的独立软件包,这一点很好,尽管它们只是我为这个问题选择的示例;-)一个问题:为什么PSR-4既需要名称空间又需要目录,为什么它们不喜欢只使用名称空间?@AmarjeetChaudhary您可以根据自己的喜好定义PSR-4结构的起始目录,但是您必须以某种方式提供目录,否则您怎么知道从哪里开始查找?定义项目的根目录不是明智的默认设置,因为像
README
composer.json
.gitignore
这样的元数据通常存储在那里。将任何其他目录定义为默认目录也会带来如何商定名称的问题
src
似乎是许多项目的常见选择,但并不是每个人都必须这样做。@sven我可能缺少一些基本概念,但根据这个家伙(),我们在composer.json文件中所做的是,将一些php文件路径转储到composer的autoload.php中,为什么我们不能只通过名称空间来识别这些路径?@AmarjeetChaudhary那个家伙在定义自动加载方面和我做的完全一样。然而,他声称“您必须导入名称空间”(部分“如何自动加载PSR-4方式?”字母“e”),这是错误的-您不必,您可以。导入名称空间与自动加载无关,因此Composer不受影响。导入就像告诉PHP“看,我认为有一个类名为
Foo\Bar
,我只在这个文件中编写
Bar
”,PHP将把你的
Bar
扩展到
Foo\Bar
——只有当这个类真正使用时,PHP才会触发自动加载。