PSR-0 is not a solution it is a bypass!
Published on 2013-04-23.
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. 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 have 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.
At the PHP Tek conference in 2009, people from various framework projects discussed their options for better coorporation between projects. They decided to create the PHP-FIG 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.
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 PHP-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 PHP-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:
\<Vendor Name>\(<Namespace>\)*<Class Name>
- 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
DIRECTORY_SEPARATOR
. 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.
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 from PHP-FIG 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 in PHP, but the implementation of the PSR-0 solution is in my humble opinion 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?
Let's consider what such an approach should do different:
- 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 list above addresses is the very reason why PHP-FIG created the PSR-0 standard in the first place, but instead of solving the problems by developing an autoloader that can deal with these issues, they created a set of restrictions in order to avoid the issues!
As a result PSR-0 is not a solution, it is a bypass.
The PSR-0 autoloader is a bypass because it will only work with the projects that follow the restrictions of PSR-0. 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 be right back at square one.
Several alternative approaches have been suggested, but they were all rejected by PHP-FIG because PSR-0 fits extremely well with the current frameworks and libraries. Since many new projects have already adopted the PSR-0 in the last couple of years they are less open to critique.
A real and practical alternative that solves all the above problems is PHP Autoload Builder (phpab). phpab was first commited in 2010, a year after the initial development of PSR-0.
The PHP Autoload Builder CLI 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 provides is that it is necessary to recreate the autoload file every time a new class is created. However, this is not really a problem, it can easily be automated. If you use some kind of version control system, you can create a "commit hook" that takes care of the re-generation of the autoload file in case a new class file has been 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 is a shame how closed the PHP-FIG is to critique because rather than having the entire PHP community benefit from the work they do they are limiting the benefits to framework and library developers.