与 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
处于同一级别的文件夹的约定是什么?例如tests
、public
、config
等等等等
(我知道有些人会评论命名空间测试的意义,但想象一个大型项目有很多单独的包,每个包都有自己的测试,但有可以在包之间重复使用的通用测试。)
我看到了使用 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\Fooable
,src/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 的认知负担,意味着编写测试的工作量更大,这降低了我编写测试的欲望。因此,您可能会说在源和测试之间共享命名空间降低了编写测试的障碍。
归根结底,源码组织的问题,真正落到了每个项目身上,建立一个促进高效开发和合理构建的布局。我会说尝试一个并没有什么坏处,如果它不成功则重构。
PSR-4 的当前约定是将 src
文件夹命名为 Vendor\Package
。然后使用目录结构对其中的任何文件进行命名空间。所以
src/Model/MyModel.php
使用
namespace Vendor\Package\Model;
class MyModel {...}
这对于 src
文件夹中的任何文件夹都很直观,但是与 src
处于同一级别的文件夹的约定是什么?例如tests
、public
、config
等等等等
(我知道有些人会评论命名空间测试的意义,但想象一个大型项目有很多单独的包,每个包都有自己的测试,但有可以在包之间重复使用的通用测试。)
我看到了使用 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\Fooable
,src/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 的认知负担,意味着编写测试的工作量更大,这降低了我编写测试的欲望。因此,您可能会说在源和测试之间共享命名空间降低了编写测试的障碍。
归根结底,源码组织的问题,真正落到了每个项目身上,建立一个促进高效开发和合理构建的布局。我会说尝试一个并没有什么坏处,如果它不成功则重构。