The current convention for PSR-4 is to namespace the src
folder as Vendor\Package
. Any file within is then namespaced using the directory structure. so
src/Model/MyModel.php
uses
namespace Vendor\Package\Model;
class MyModel {...}
This is intuitive for any folders within the src
folder, but what is the convention for folders on the same level as src
? For example tests
, public
, config
etc etc
(I understand some people will comment about the point of namespacing tests but image a large project with lots of individual packages each with their own tests but with common tests that can be reused between packages.)
I have seen suggestions of using Vendor\Package\Tests
but to me, following the src
convention, this gives the impression that there is a Tests
folder within src
, which is not the case. Although if there was a Tests
folder within src
then those namespaces would conflict?
Namespaces should group code that logically and semantically belong together. In my mind, configurations, routers, and tests all belong together as part of the application as a whole, and thus my configurations tend to have them all share namespace:
autoload: { "psr-4": { "Vendor\\Package\\": [ "public", "conf", "src" ] } }
autoload-dev: { "psr-4": { "Vendor\\Package\\": [ "tests" ] } }
Of course, by sharing namespaces, that means each artifact has to be classified (often by its "kind") to prevent class name collisions. For example, Vendor\Package\Foo
might involve the following related artifacts:
Vendor\Package\FooTest
, the unit test for foo in tests/FooTest.php
Vendor\Package\FooIntegrationTest
, an integration test specifically covering foo in tests/FooIntegrationTest.php
Vendor\Package\AbstractFoo
, the base for family members of foo in src/AbstractFoo.php
Vendor\Package\Fooable
, the interface for foo kind of things in src/Fooable.php
Along these lines, you might consider separating out your different kinds of code into different directories, rather than one "catch-all" src
. For large projects, this makes finding particular kinds of files easier, but is likely overkill for libraries or small applications:
autoload: {
"psr-4": {
"Vendor\\Package\\": [
"public", "conf", "lib", "view", "contract", "exception"
]
}
}
As for "convention", I particularly find sharing namespaces between source code and tests to be convenient and easy, because when I want to test Foo I don't have to juggle namespaces to get at it.
// 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;
}
}
One extra line in every test file, plus the cognitive load of having to find the SUT when writing a test meant more work for writing tests, which lowered my desire to write tests. So, you might say that sharing namespaces between source and tests lowers the barriers to writing tests.
In the end, questions of source code organization really fall to each project to establish a layout that promotes efficient development and reasonable builds. I'd say it can't hurt to try one, and refactor if it's not working out.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With