I was wrong about PSR-11
Back in January 2017, the PHP Framework Interoperability Group (FIG) reviewed and passed PSR-11, the "Container Interface" specification. It was a very simplistic 2-method interface for Dependency Injection Containers, which had been worked on for some time by a small group. (This was before FIG had formal Working Groups, but "container-interop" was one of the effectively proto-Working Groups that were floating about.)
PSR-11 passed overwhelmingly, 23 to 1 out of the FIG member projects at the time. The lone holdout was Drupal, for which at the time I was the voting representative.
Two and a half years later, I will say I was wrong, and PSR-11 has been a net-win for PHP.
At the time, my reasons for voting against PSR-11 were threefold:
- I was concered (as were many) that standardizing a way to pull values out of a Container Service-Locator-style would lead to more people using Containers as a Service Locator.
- PSR-11 only standardized how to get values out of a Container, not how to put them in. The latter I saw as the far more useful thing to standardize, so PSR-11 was tackling the wrong part of the problem and onl half-solving the problem.
- The spec only defines a
NotFoundExceptionInterface
and does not differentiate between that and "your service is defined but its definition is broken" (due to a missing dependency or something), and I felt it should define a more specific exception for that.
And of course, speaking for Drupal at the time, the Drupal leadership was largely meh on it if not negative. Although to be fair, the only person in Drupal's leadership who ever truely gave a damn about standards and compatibility was me so their hostility was hardly out of character.
So what's changed in two and a half years?
For the first point... that fear hasn't materialized. As far as I can tell PSR-11 hasn't had a side effect of people using Service Locators more. (Laravel's facades have the same negative effect, but that's independent of PSR-11.)
For the third point, well, nothing. I still think it should have been a separate exception interface but the world hasn't ended, so ¯_(ツ)_/¯.
For the second, what's changed is working on PSR-14, the Event Dispatcher spec. Specifically, two things.
For one, PSR-14 also didn't standardize how to put Listeners into a Provider. I wanted to; I again saw the job as half-done without that. However, it became clear while working on the spec just how impossible it would be to standardize that part; there's just too many ways for a Provider to get populated. Plus, while it wasn't our initial intent, the result of the Provider design being super composable (especially with the AggregateProvider
and DelegatingProvider
utility classes) is, I feel, far better and more flexible a way to "put Listeners into the Provider" than any specific API we could have developed.
Which... interestingly enough is very similar to the "delegating lookup" logic that was in early PSR-11 drafts before being removed late as unnecessary. "A container can delegate looking up a service to another container" is the same basic argument as "A Provider can delegate finding Listeners to other Providers". And... I have to admit, it's a pretty nice design.
For another, while working on Tukio (my PSR-14 implementation) I wanted to support lazy-instantiated Listeners via services, which is a very common usecase in the wild. That ended up being stupidly easy, thanks to PSR-11. Because PSR-11 containers are so prevalent today (I don't think there are any that aren't PSR-11 compatible anymore), supporting Listeners that are a service in a PSR-11 container basically means supporting every Container in the PHP world, and the simple API made adding that support quick work.
So there you have it; one concern was unfounded, one I've switched sides on with more experience, and one, well, nobody's perfect. :-)
So even if it's rather belated, nice work PSR-11 team! This is one of those cases where I am glad to have been wrong.