Composer and PSR-0: Friends, Not Relatives

Posted: 2013-05-07
Category: PHP

As a huge proponent of Composer, a happy user of PSR-0 and a voting member on the PHP-FIG I get into plenty of conversations about all of them and it worries me how much confusion there is in the community about these things not actually being related.

To many of you this will be preaching to the choir, but this will hopefully clear a few things up for many or at the very least be a handy resource to link people to when they show signs of getting confused between the two. I'm sorry if this bores you silly.

  1. PSR-0 came out in 2009
  2. Composer came out in 2011
  3. Composer happens to support PSR-0
  4. PSR-0 code can be installed and autoloaded using Composer

It seems that a lot of folks discover Composer and PSR-0 at the same time and seem to assume they are the same thing - especially since both Composer and PSR-0 have the idea of a "vendor" and a "package", but those two things are not related to each other either.

These are a few points that I have wanted to clarify during some strange conversations over the last few weeks.

Vendor Name Confusion

This comes up fairly often, and was actually asked on the composer-dev mailing list the other day.

If you use PSR-0 and Composer then you have two different vendor names, and two different package names.

Why? Because even code that is not using PSR-0 needs vendors and package names, so code like the Facebook SDK can be made Composer compliant by just adding a composer.json, and doesn't need to be recoded to PSR-0.

  • Facebook => vendor/facebook/php-sdk/src/facebook.php

If you do want to use PSR-0 for your classes then you need to make PHP vendors and packages too, but remember your code could be sitting along-side non-PSR-0 code, so you still need these Composer specific vendors for your code. This means your package could look like this:

  • Phil\Kitten\Snuggles => vendor/phil/kittens/src/Phil/Kitten/Snuggles.php

Now, while you might be annoyed at having to have two lots of vendors, you can see here that they might not be identical. I might want my PHP namespaces to be singular, and my Composer package could well be plural.

This goes even further when you consider the fact that PHP namespaces do not allow hyphens, but composer packages totally do, because why not?

  • Symfony\Component\BrowserKit\Cookie => vendor/symfony/browser-kit/src/Symfony/Components/BrowserKit/Cookie.php

Or these names could be completely different from their Composer names:

  • Illuminate\Validation\ValidationServiceProvider => vendor/laravel/framework/src/Illuminate/Validation/ValidationServiceProvider.php

Why is that totally different? Because Laravel is a framework, made up of lots of different components. These components are under the "Illuminate" namespace and can be used in any application you like. Together, it becomes the Laravel framework.

So, these two have nothing to do with each other, and lets not assume they need to be the same thing, because that only covers a fraction of the use-cases that PSR-0 supports.

Saying Composer packages are not PSR-0

This has come up so many times and it's silly.

"Composer is meant to support PSR-0, but I have all these lower-case folders!"

Uck. Having a sub-directories such as "src/", "tests/" etc does not make this code Non-PSR-0. PSR-0 autoloaders are able to register to multiple points. Each location you register is bound to a namespace prefix, then it will load from there. If you are using Composer packages you will point your prefix at your src/ folder:

"autoload": {
    "psr-0": { "Foo\Upload": "src" }
}

Everything inside there is then considered to be PSR-0, everything outside is irrelevant.

So this code is specifically required to live in Composer? I thought you said…?

Nope. This code is developed to be a component, which bundles its src/, its tests/ and a README no doubt. It happens to be installable by Composer, or Unicorn (the dependency manager I made up earlier), but could totally work on its own without breaking the PSR-0 spec at all.

If you wanted this code to live outside of Composer then you could do one of two things:

  1. Copy and paste the contents of src/ into one main PSR-0 folder in your application - like its 2001 - and use the example autoloader.
  2. Copy and paste the whole component codebase and use the SplClassLoader to register Foo\Upload to src/ yourself.

Doing either of these is a bit weird, because… well why would you?

If you want to install components, then use something that is designed to install them (Composer or Unicorn), and if you want to autoload your own code put it directly into an autoloadable area within your application.

PyroCMS does both, it has:

  • system/cms/modules/*/src/
  • system/cms/src/
  • vendor/*/*/(lib/|src/)

Note: That regex is just there to highlight that Composer devs can do what they like, it doesn't matter.

The point here is that PyroCMS supports custom PSR-0 autoloading locations (one global, one in each module) and a main vendor/ folder which has a mixture of PSR-0 and random classmapped code.

PSR-0 must stay "Implementation Agnostic"

This is another conversation that has popped up a few times. People want to see Composer making changes to bring PSR-0 support more into the core, or want PSR-0 to change based around how Composer works. That would be nuts, and luckily nobody on the FIG has been vocal about having any interest in doing this.

Realistically Composer is the only dependency manager out there at the moment, but theoretically somebody else could build a bigger and better system tomorrow. The entire PHP community could immediately fall in love with this dependency manager, instantly throwing Composer out faster than plague-ridden step-mothers in 1349, and they could both support PSR-0 equally.

You might need to make a unicorn.json file to sit next to your composer.json and it could work with both systems just as easily. No other changes should be required to switch.

Having a spec that relies on a specific structure being set up by a piece of third-party software would be detrimental to the entire community, which is why things like PHPab are awesome, but not a standard.

Composer must stay "Specification Agnostic"

What will happen when a new autoloading standard is released? We'll be finding out fairly soon, as the PHP-FIG are working on an awesome proposal called the "Package Autoloader". This is codenamed PSR-X and will most likely be released as PSR-4, and is incredibly similar to PSR-0 code with a few super-handy tweaks.

To put it simply, PSR-X no longer translates underscores to directory separators (which was in there for legacy PEAR/Zend type stuff) and allows package developers to potentially skip out the PHP namespace by inferring it:

  • Symfony\Component\BrowserKit\Cookie => vendor/symfony/browser-kit/src/Cookie.php

For this to work there will be a slightly different sample implementation of the autoloader, which will accept arguments that basically convey the message that Symfony\Component\BrowserKit maps to vendor/symfony/browser-kit, and instead of requiring the extra folder structure it will just start looking for the next folder or file. In other words, you are simply deleting the Symfony/Components/BrowserKit folders and moving everything up a few folders. Simple!

If Composer was all tied up on PSR-0 then this would never work, and all the old stuff would break. As it stands it will be insanely easy for Composer to integrate PSR-X/PSR-4? support into Composer. There will be some logic that goes into the composer.json which will look something like:

"autoload": {
    "psr-4": { "Foo\Upload": "src" }
}

This would work exactly the same, but you just skip a few folders. Whoopdydoop!

Composer, PSR-0, PSR-X and their separation are all important

PSR-X needs to be separate to avoid fucking with PSR-0 users. They both need to be separate from Composer to let Composer do its thing while they do theirs.

I've heard some chatter about "which is more important" and I think even wondering about that is pointless. PHP is an ecosystem, and in an ecosystem everything plays its part. Trees are obviously important, but I remember having some drunken conversation where somebody explained to me how the planet Earth would pretty much die over a few decades if there were no ants.

Whatever type of "a bird flaps its wings and we have dinosaurs again" story you want to go with, it is important to remember that every single part of an ecosystem is important. If you hate ants then don't buy an ant-farm, or go to the rain forest but if you kill them all off there will be a lot of upset ant-eaters. Or something.

Comments

Gravatar
Amy Stephen

2013-05-07

Phil - this is a fairly decent post. Thanks for sharing it. =)

There are a few finer points I'd like to mention that might help you understand the general confusion from those of us who have not had the history, you have had. Bear in mind, please, that my comments are shared to help reduce some of the frustration you are feeling, not to increase it.

On the PSR-0/Packagist relationship: please remember, it was only a few weeks ago when the instructions were changed on the "Naming your package" page to remove the instruction that the Vendor name must follow the PSR-0 standard. https://github.com/composer/packagist/commit/2f3d9e6cfd7eefe0daaa0950a2cb3a9a97589edf

People are trying to follow FIG standards and comply with Composer/Packagist, so these instructions are very important and have unfortunately created part of the problem.

Also, it's good to remind people that the src/ folder is nothing more than a common practice amongst many PHP developers. There is no requirement by any PSR indicating how a dev must store their repository. The fact that the folder gets mentioned in conjunction with so many PSR-0 posts creates confusion, too.

Regarding PSR-X and PSR-0: maybe the message folks need to understand is that if they are already PSR-0 compliant, then they will be PSR-X compliant, too. PSR-X should resolve much of the concerns people had about the length of the install folders, and do so in a way that doesn't require Composer change, and still supports the common practice of the src/ folder.

So, personally, I think it's time to end PSR-0 and move towards PSR-X, being very clear to people that if they are already PSR-0 compliant -- they are automatically inline with PSR-X, without any changes required. That way, we move on and you don't have to be so frustrated, well, we'll have new frustrations for you, so hugs.

In general, I think devs will be pleased to see PSR-X addresses those basic concerns folks have had.

Thanks again for your post and for your work on FIG.

Gravatar

2013-05-07

Hey Amy,

I'm glad to see you're a fan of PSR-X, it seems like not only yesterday I was trying to explain to you why it solved all of your problems.

We definitely won't be "ending" PSR-0 any time soon, but having the two available will certainly help out a lot of people.

Gravatar
Cory Comer

2013-05-08

I fail to see how the reduction of at-a-glance information helps anyone.

/var/www/example.com/vendor/awsome-sauce/src/Service.php

What is the FQCN of the class that's inside of this file?

The only argument I've seen for PSR-X comes from people using Composer and PSR-0 libraries together, which seems incredibly short-sighted to base PSR-X on. PSR-0 handles autoloading just fine, devoid of the use of Composer, does PSR-X make any sense? I agree with your closing statement - "PSR-X needs to be separate to avoid fucking with PSR-0 users. They both need to be separate from Composer to let Composer do its thing while they do theirs.". If the voting members of PHP-FIG feel the need to implement "unique snowflake" PSRs, that's not going to be avoided I suppose; I just hope they keep them contained and don't replace or amend existing PSRs like PSR-0.

Gravatar

2013-05-08

Cory: Which is more helpful:

/var/www/example.com/vendor/awsome-sauce/src/AwesomeSauce/Service.php

or

/var/www/example.com/vendor/awsome-sauce/src/Service.php

The answer is neither, because it's painfully bloody obvious what you are talking about either way.

"The only argument I've seen for PSR-X comes from people using Composer and PSR-0 libraries together"

Nope, PyroCMS would benefit from this too.

/system/cms/modules/users/src/Pyro/Module/Users/Model/Group.php

becomes

/system/cms/modules/users/src/Model/Group.php

Tadaaaaaaa.

Nobody is going to delete PSR-0 just because a new thing is happening, don't get weird.

Gravatar
Cory Comer

2013-05-08

Phil,

It is not painfully bloody obvious what FQCN is in a file called Service.php when, as I understand the suggested proposal for package autoloading, with PSR-X you'd be able to map the Awesome\Sauce\Stdlib namespace to the directory: /var/www/example.com/vendor/awesome-sauce/src/, which would allow the above mentioned file (/var/www/example.com/vendor/awesome-sauce/src/Service.php) to contain the class Awesome\Framework\Stdlib\Service().

Correct me if I'm wrong please, because it seems like this is a step backwards.

As for the example you use with Pyro, based on the previous directory structure, I assume the file:

/var/www/example.com/vendor/pyro/system/cms/modules/users/src/Model/Group.php

.. would contain a class called Pyro\Module\Users\Model\Group() I guess?

Wut?

Gravatar

2013-05-08

Yes, correct, see its easy.

When you click that file, you'll find out soon enough.

You're not going to be lost at sea, desperately searching for land for months. It's going to be very obvious very quickly what is going on.

Gravatar
Cory Comer

2013-05-08

So before hand, using PSR-0, I could look at the file:

/var/www/example.com/vendor/pryo/system/cms/modules/users/src/Pyro/Module/Users/Model/Group.php

... and I could, at-a-glance, discern that the class inside was Pyro\Module\Users\Model\Group(). With the package mapping proposal in PSR-X, without actually opening the file or checking the autoload configuration, I'm left clueless as to what the actual FQCN might be.

Again, I reiterate, it seems like a step backwards for a PSR to standardize what, in my opinion, seems like a very bad practice and a loss of informative naming conventions, but I digress; your blog post was about the relationship between PSR-0 and the package naming convention of Composer. I don't want to turn your comments into yet-another-debate about package mapping and PSR-X.

As for the content of your post, I think you've done a great job explaining the differences between Composer's vendor package naming convention and the existing PSR-0 autoloading naming convention. Hopefully it stimulates more conversation concerning standards independent of conventions implemented by a dependency management tool such as Composer.

Gravatar
Ross

2013-05-08

You said this: If you use PSR-0 and Composer then you have two different vendor names, and two different package names.

This is a statement, right? Not one of the myths/confusions? You then go on to explain why, which I'm sure is right, but I can not place any of it in a meaningful context.

I understand namespacing in PHP, I understand PSR-0 (at least I think I do), but I have a lot of trouble interpreting the paragraph that follows.

"Code not using PSR-0 needs packages and vendor names"...? What?

Do you mean you can have composer supporting non PSR-0 libraries by providing it with a package and vendor name?

And if you do use PSR-0, "you need to create vendors and packages" too? Isn't that just a consequence of the naming structure n your namespace corresponding to the file structure?

Wahhhh! I seem to be missing either a lot of subtext or precursor information to make sense of the start of this article.

I feel like I need to read an article on how Composer UTILISES PSR-0 to achieve some of its end goals because I am losssssssssst.

Gravatar

2013-05-08

Cory: Agreed some folks will see it as being "less readable", I see it as being less verbose. Not everything will fit into PSR-X and anything that does should be simple enough that its not a problem. Besides, if everyone agreed on every part of a PSR then I wouldn't have anything to blog about. :)

Ross: Yep, you have a Composer vendor and a composer package name. I gave the example of Facebook:

facebook/php-sdk

"facebok" is a vendor, "php-sdk" is a package. But, that is obviously not a PHP namespace at all. The Facebook SDK does not use namespaces (and that of course means they cannot be PSR-0).

The code inside the package can be anything, so if they happen to use PSR-0 then they need PHP namespaces, and the folder structure that goes with it.

Does that make more sense?

Gravatar
Ross

2013-05-09

I get it now Phil, thanks. I think the confusion comes from using composer as an end user who has never published a package through it, yet writing PHP code that relies on composer packages where the namespacing is taken care of and intuitively handled by my IDE (Phpstorm).

Posting comments after one month has been disabled.