PSR-4, really ?

Submitted by Frederic Marand on

Yesterday, Seldaek committed PSR-4 support to Composer, as his New Year's Day gift to the PHP community.

So, since I always supported PSR-4 in FIG discussions, and after the tl;dr discussion about it regarding autoloading in Drupal 8, I jumped on the occasion and converted the code base for PlusVite to PSR-4 to get an idea of how PSR-4 "felt" in practice.

A the documentation explains, to convert from PSR-0 to PSR-4 to shorten paths, the change is extremely simple: just edit your composer.json and change it like this:

  PSR-0 PSR-4 with PSR-0 layout Pure PSR-4
\Foo\Bar\Bazclass is in src/Foo/Bar/Baz.php src/Foo/Bar/Baz.php src/Baz.php
composer.json contains "psr-0": { "Foo\\Bar\\": "src/" } "psr-4": { "Foo\\Bar\\": "src/Foo/Bar/" } "psr-4": { "Foo\\Bar\\": "src/" }

Of course, removing two levels of directories provided the expected small degree of instant gratification, making everything seem simpler. But then, doubt appears: maybe this is just because I've been using PSR-0 for too long (3 years, already ?), but now, seeing these namespaced classes/interfaces/traits in short paths like src/Baz.php for a simple project like this seems to be hiding information, degrading DX instead of improving it. Eewww !

Now, in Drupal 8, the situation is different: classes core modules are located under

core/modules/(module)/lib/Drupal/(module)/(subnamespace hierarchy)/someclass.php

while PSR-4 will change this to

core/modules/(module)/lib/(subnamespace hierarchy)/someclass.php

so the "hiding" effect will not be the same, since the name of the module (hence the namespace) will be in plain sight. But still, this is an unexpected feeling and I hope we will not regret it later on.

You hit a nerve here! There has been quite some resistance against PSR-4 in the Drupal thread, but I did not have much sympathy with the arguments. But the "hiding information" seems like a valid and relevant point!

I think it all boils down to how much you mentally identify the module directory with the module namespace. If the package namespace is rather arbitrary, then the two empty parent directories will immediately tell you about the package namespace (or the module namespace, in our case).

Now I am confused :)

yched (not verified)

Mon, 2014-01-06 10:27

The "hiding information" or "eating part of the namespace root" effect only affects full libs.
\Drupal\module\Foo\Bar\Baz being in [module]/lib/Foo/Bar/Baz.php hides no information and only keeps the "intuitive, not needlessly verbose" effect.

Which is why "PSR-0 for external libs" and "PSR-4 for drupal modules" is a good fit.

Ross (not verified)

Mon, 2014-06-09 14:18

I'm trying to move some of my classes on PSR-4 but I'm feeling like it introduce a lot of confusion.

Now it is more than one month I moved some side libraries with PSR-4 standard but I'm thinking to switch back to PSR-0.

Despite the duplicated vendor-name/module in PSR-0 I feel more comfortable with this standard.

When I build a library I would like to have a structure:

src/CompanyName/Module/[Sub/]Class.php
tests/CompanyName/Module/[Sub/]Class.php
...
xxx/CompanyName/Module/[Sub/]Class.php

than:

/CompanyName/Module/src/[Sub/]Class.php
/CompanyName/Module/tests/[Sub/]Class.php
...
/CompanyName/Module/xxx/[Sub/]Class.php

when I use that library somewhere, it will be installed in vendor/companyname/module/src/CompanyName/Module/[Sub/]Class.php (that is not cool obviously), but my point is, once Composer installs that for you in the vendor dir, you don't have to care at what inside vendor, don't you?

I still think PSR-0 is the best way to setup directory structure, I don't understand why Composer installs it in that way??? Maybe I lost something but I would be more than happy to understand why composer can't manage PSR-0 to install libraries without "companyname/module/src" and starts directly from the NS.

vendor/CompanyName/Module/[Sub/]Class.php

am I losing something?

Obviously It's my personal tough.
Rosario

Frederic Marand

Tue, 2014-06-10 11:21

In reply to by Ross (not verified)

I do not really see your point: while working on the module itself, you do not even need to include CompanyName/Module, since this is your "main project" at this point, and you could just as well use a layout like:

src/[Sub/]Class.php
test/[Sub/]Class.php

This is only needed to group projects by vendor to avoid name collisions. If the paths started by src|test instead of the company name, you could get a vendor/src/(companies) directory, meaning vendor/src would mix vendors and vendor/test would mix them too. The current Composer layout seems better for packaging.

Also, note that :

  • this is in no way related to PSR-4
  • Composer is but one implementation (albeit the most popular) of PSR-0, PSR-4 and other autoloading strategies : you could just as well use your own autoloader using a layout different from Composer's. It could even still use Packagist as its main repository source.