PSR-0 is not a solution it is a bypass!

Posted on 23.04.2013 by Kim N. Lesmer.
This is a small article that takes an objective look at the PSR-0 autoloader "standard" implemented by PHP-FIG.

First some history

PHP has never had any kind of uniform standard for writing code and with good reason. Code style is not something that the programming language should enforce and it is only natural that different projects adopt and implement a specific code style that represents that particular project. That is the way it has always been in most other programming languages as well.

People who maintain various projects implements their own naming conventions and coding style guidelines. When someone want to contribute some code he or she naturally adopts the style of the project and changes the style in other projects. Some developers has chosen to inherit a well-documented code style, such as PEAR or Zend Framework, while others has chosen to write their own code style guide from scratch.

This is the natural approach of code style and naming conventions.

Then PHP-FIG came along. The PHP-FIG stands for PHP Framework Interoperability Group. The name until recently was "PHP Standards Group" but the group had to change the name as the group doesn't represent any official PHP standard.

At the PHP Tek conference in 2009, people from various framework projects discussed their options for better corporation between projects. They decided to create the PHP-FIG group.

Even though the name of this group explicitly refers to frameworks, developers representing all sorts of projects have been accepted as voting members.

The goal of the FIG is to create a dialogue between project representatives, with the aim of finding ways to work together (interoperability).

PSR-0: Autoloader Standard

The first thing the FIG implemented was the "PSR-0: Autoloader Standard".

The PSR-0 is a "standard" recommendation that describes "the mandatory requirements that must be adhered to for autoloader interoperability."

PSR-0 is a huge step forward for reusable code, they claim.

If a project follows the PSR-0 standard and its components are loosely coupled, you can take those components, place them within a "vendor" directory, and use a PSR-0 compliant autoloader to include those components.

But let us take a step back and look at the solution objectively. Here's a summary of the mandatory demands of the PSR-0 Autoloader Standard:

  • A fully-qualified namespace and class must have the following structure \()*
  • Each namespace must have a top-level namespace ("Vendor Name").
  • Each namespace separator is converted to a DIRECTORY_SEPARATOR when loading from the file system.
  • Each _ character in the CLASS NAME is converted to a DIRECTORYSEPARATOR. The character has no special meaning in the namespace.
  • The fully-qualified namespace and class is suffixed with .php when loading from the file system.

Now, that's quite a big set of restrictions, but what does it really mean?

It means that in order for the namespaces to work with the PSR-0 autoloader your project is forced to follow a very restricted directory structure that really only fits with frameworks and libraries.

It also means that if you are working with any kind of legacy code, in this case code that was produced before the implementation of the PSR-0, then you cannot use the PSR-0 autoloader on that code and you have to use yet another, or as in most cases, several other autoloaders.

Anybody who has ever dealt with large PHP libraries knows what difficulties using several different autoloaders produces, but since the PSR-0 cannot work with code that doesn't follow the above restrictions, the only other viable solution is to reorganize the old code, which really isn't a viable solution at all.

Within the PHP-FIG this isn't regarded as a problem. They are quite content with the situation because it suits the work they are doing very well. They all work on new code that implements the PSR-0 standard.

If anyone has a problem with the restrictions of PSR-0 then the answer is simple: Don't use the PSR-0 standard.

While it has been clear from the ongoing that PHP-FIG would really like to make a huge impact on the PHP community in general, and not just on people who work on frameworks and libraries, the solution they provide ignore the needs of many people within the PHP community.

The idea behind PHP-FIG is not a bad one, on the contrary, it is about time something like this has happened, but the implementation of the PSR-0 solution is bad.

A better approach - theory

Now, what if we could have the same results as those the PHP-FIG is attempting to create, but in a better way?

Lets consider what such an approach should do differently:

  • A single and very simple autoloader.
  • Fully-qualified namespace must be supported for all new code.
  • Legacy code without namespaces should work too.
  • No restrictions on directory structure what so ever.
  • No restrictions on class names as many legacy code libraries use the old _ style in class names.
  • No conversion of _ into DIRECTORY_SEPARATOR.

The problems that the above normally produce is the very reason why the PHP-FIG created the PSR-0 standard in the first place, but instead of solving the problem by developing an autoloader that can deal with those issues, they created a set of restrictions in order to avoid the problems. As a result the PSR-0 solution is not a solution, it is a bypass.

The PSR-0 autoloader is a bypass because it will only work with those projects that follows the restrictions and all other projects are then faced with the difficult situation of either rejecting the PSR-0 or use it together with a set of other autoloaders, and then they right back at square one.

A better approach - practical

Several different and alternative approaches has been suggested, but all rejected by the PHP-FIG because they really don't care about alternatives as the current PSR-0 solutions fits very well with the current frameworks and libraries. And since many new projects has already adopted the PSR-0 in the last couple of years they are less open to critique.

One practical solution that solves all the above is PHPab.

PHPab was first commited in 2010, a year after the initial development of PSR-0, yet it has never really seriously been considered as a viable replacement or solution to the PSR-0 autoloader mainly because the project leaders has long since moved passed the original discussions about the standard for an autoloader.

The PHP AutoloadBuilder CLI tool PHPab is a command line application to automate the process of generating an autoload require file with the option of creating static require lists as well as phar archives.

PHPab generates one single and simple autoloader that can load all libraries, frameworks, classes (new and legacy), with or without the usage of namespaces.

PHPab features:

  • Scan multiple directories recursively in one run.
  • Template based autoload code.
  • Custom variables for templates.
  • Compatibility mode for PHP 5.2 compliant autoloader.
  • Case sensitive as well as case insensitive classname mapping.
  • Phar generation, with or without compression and openssl key signing.
  • Static require list generation.
  • Linting of generated code.

The only minor drawback from the solution that PHPab creates is that it is necessary to recreate the autoload file every time a new class is created.

However, this is not a problem because it can easily be automated. Since almost all PHP projects, legacy as well as new, all use some kind of revision control system, the problem is solved simply by creating a commit hook that takes care of the re-generation of the autoload file in case a new class file is added to the project.

In Git, for example, the generation of the autoload file can be made automatic by the usage of a pre-commit hook that contains the PHPab script. Here's a simple example:

#!/bin/sh
phpab -b ./application/ -o application/autoload.php \
application/library/ application/internal/

Conclusion

While the work of the PHP-FIG indeed is commendable the PSR-0 autoloader solution is not.

It really is a shame how closed the PHP-FIG is to critique of their solutions, because instead of the entire PHP community benefiting from their work (which really also was what they originally intended clearly revealed by the first name of the group) they limit the benefits to frameworks and libraries by their restrictions.

However, while new framework projects and library projects seem to benefit, because PHP-FIG has already made a huge impact on the PHP community, even projects outside the scope of frameworks and libraries has also adopted the PHP-FIG standards, but as history has taught, when someone uses a restricted and backwards solution, as the PSR-0 really is, then it will eventually be dropped by the majority in favor of a simpler and more practical approach.

Right now many projects has adopted and implemented the PSR-0 autoloader, but many many more projects has also rejected it and keep doing business as usual, all that is needed is another standard group with no bias towards any particular type of project, and then it will become possible for the PHP community to really move forward.