与 src 处于同一级别的文件夹的 PSR-4 命名空间约定

PSR-4 namespace conventions for folders on same level as src

PSR-4 的当前约定是将 src 文件夹命名为 Vendor\Package。然后使用目录结构对其中的任何文件进行命名空间。所以

src/Model/MyModel.php

使用

namespace Vendor\Package\Model;

class MyModel {...}

这对于 src 文件夹中的任何文件夹都很直观,但是与 src 处于同一级别的文件夹的约定是什么?例如testspublicconfig等等等等

(我知道有些人会评论命名空间测试的意​​义,但想象一个大型项目有很多单独的包,每个包都有自己的测试,但有可以在包之间重复使用的通用测试。)

我看到了使用 Vendor\Package\Tests 的建议,但对我来说,遵循 src 惯例,这给人的印象是 src 中有一个 Tests 文件夹,事实并非如此。虽然如果 src 中的 Tests 文件夹,那么这些命名空间会发生冲突吗?

命名空间应该将逻辑上和语义上属于一起的代码分组。在我看来,配置、路由器和测试都属于整个应用程序的一部分,因此我的配置倾向于让它们共享名称空间:

autoload: { "psr-4": { "Vendor\Package\": [ "public", "conf", "src" ] } }
autoload-dev: { "psr-4": { "Vendor\Package\": [ "tests" ] } }

当然,通过共享名称空间,这意味着每个工件都必须 class 化(通常由其 "kind" 化)以防止 class 名称冲突。例如,Vendor\Package\Foo 可能涉及以下相关工件:

  • Vendor\Package\FooTest, tests/FooTest.php
  • 中foo的单元测试
  • Vendor\Package\FooIntegrationTest,专门针对 tests/FooIntegrationTest.php
  • 中的 foo 的集成测试
  • Vendor\Package\AbstractFoo, src/AbstractFoo.php
  • 中foo家族成员的基地
  • Vendor\Package\Fooablesrc/Fooable.php
  • 中的 foo 接口

沿着这些思路,您可以考虑将不同类型的代码分离到不同的目录中,而不是一个 "catch-all" src。对于大型项目,这使得查找特定类型的文件更加容易,但对于库或小型应用程序来说可能有点过分了:

autoload: { 
    "psr-4": {
        "Vendor\Package\": [
            "public", "conf", "lib", "view", "contract", "exception"
        ]
    }
}

至于 "convention",我特别发现在源代码和测试之间共享命名空间既方便又容易,因为当我想测试 Foo 时,我不必为了获得它而折腾命名空间。

// tests/Something/FooTest.php
namespace Vendor\Package\Test\Something;
use Vendor\Package\Test\BaseTestCase;
use Vendor\Package\Something\Foo; // extra work I don't want to do

class FooTest extends BaseTestCase {
    public function testX() {
        $sut = new Foo;
    }
}

每个测试文件多一行,加上编写测试时必须查找 SUT 的认知负担,意味着编写测试的工作量更大,这降低了我编写测试的欲望。因此,您可能会说在源和测试之间共享命名空间降低了编写测试的障碍。

归根结底,源码组织的问题,真正落到了每个项目身上,建立一个促进高效开发和合理构建的布局。我会说尝试一个并没有什么坏处,如果它不成功则重构。