Battle of the Autoloaders: PSR-0 vs. PSR-4

Tweet

If you've gone past the beginner stage in your PHP training, you've heard of PSR-0 – an autoloading standard that defines ways to automatically include PHP classes in your code without having to use statements like require and include.

PSR-0

PSR-0 looks at the namespace of a class and discerns its location on the hard drive from that bit of information. For example, the class \Zend\Mail\Message would lead to /path/to/project/lib/vendor/Zend/Mail/Message.php.

PSR-0 also supports underscores in the class names as an alternative, to make transitioning from 5.2 and earlier easier. Zend_Mail_Message would also lead to /path/to/project/lib/vendor/Zend/Mail/Message.php.

Composer

When Composer showed up and took the PHP package management world by storm, things changed. Due to some of its rules, folders often duplicated and became too deep when looking at PSR-0 class installations via Composer. For example, some folder structures ended up like this:

vendor/
    vendor_name/
        package_name/
            src/
                Vendor_Name/
                    Package_Name/
                        ClassName.php       # Vendor_Name\Package_Name\ClassName
            tests/
                Vendor_Name/
                    Package_Name/
                        ClassNameTest.php   # Vendor_Name\Package_Name\ClassNameTest

This is chaotic at best, because:

The "src" and "tests" directories have to include vendor and package directory names. This is an artifact of PSR-0 compliance.

Therefore, some highly qualified PHP devs got together and put together a suggestion for a new standard: PSR-4.

PSR-4

PSR-4 aims to complement and work together with PSR-0 where necessary, not completely replace it. It can, but doesn't have to. The main goal of PSR-4 is to remove the remnants of PSR-0 and the pre-5.3 days completely, and allow for a more concise folder structure. With PSR-4, the above folder tree would look like this:

vendor/
    vendor_name/
        package_name/
            src/
                ClassName.php       # Vendor_Name\Package_Name\ClassName
            tests/
                ClassNameTest.php   # Vendor_Name\Package_Name\ClassNameTest

Upgrading PSR-0 was not an option

because PSR-0 does not allow for an intercessory path between any portions of the class name

This is very important – it means that implementing PSR-4, while allowing for much cleaner packages, would be far more complicated to implement. We call PSR-4 package-oriented autoloading, because it favors package cleanliness before simplicity.

The chosen approach

The suggested goals are as follows: keep the PSR-0 rule that all packages must contain at least two namespace levels (vendor and package), make sure the vendor-package combo can map to any folder, and allow for an infix of folders between the vendor-package combo and the rest of the fully qualified class name.

This means we would be able to put our classes anywhere in the package code where it makes sense to us as humans, and still use them smoothly in PHP without writing alternative loading techniques or resorting to manual loading.

Furthermore, the draft explicitly states that a PSR-4 autoloader should never throw exceptions or raise errors simply because multiple autoloaders may be registered, and if one fails to load a class, others should be given the chance to do so – throwing an error and stopping the flow breaks this compatibility. If additional information about the failure is required, one should use a PSR-3 compatible logger or other arbitrary means.

As illustrated in the example file, using the PSR-4 autoloader to load classes from the following structure:

      /path/to/packages/foo-bar/
          src/
              Baz.php             # Foo\Bar\Baz
              Qux/
                  Quux.php        # Foo\Bar\Qux\Quux
          tests/
              BazTest.php         # Foo\Bar\BazTest
              Qux/
                  QuuxTest.php    # Foo\Bar\Qux\QuuxTest

would look like this:

 <?php
    // instantiate the loader
    $loader = new \Example\Psr4AutoloaderClass;

    // register the autoloader
    $loader->register();

    // register the base directories for the namespace    prefix
    $loader->addNamespace('Foo\Bar', '/path/to/packages/foo-bar/src');
    $loader->addNamespace('Foo\Bar', '/path/to/packages/foo-bar/tests');

where calling new \Foo\Bar\Qux\Quux; would attempt to load from the first registered directory, while new \Foo\Bar\Qux\QuuxTest; would attempt to load from the second.

This example also illustrates the use of multiple folders per single namespace.

Conclusion

There is no silver bullet in autoloading. Each approach brings with itself some pros and cons – PSR-4 would allow for simpler folder structures, but would prevent us from knowing the exact path of a class just by looking at the fully qualified name. PSR-0 on the other hand is chaotic on the hard drive, but supports developers who are stuck in the past (the underscore-in-class-name users) and helps us discern the location of a class just by looking at its name.

How do you feel about PSR-4? Let us know in the comments below, or express your opinion in one of the many debates.

Either way – there's no doubt package-oriented autoloading is here to stay. If not formally accepted as a standard, then custom implemented by people who need it. It's up to us to join the discussion and improve the notion enough to reach this formal state.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • Henrik Bjørnskov

    People should not go to the thread and vote for or against. The vote is only for FIG Member Projects, all other votes than theirs are invalid and will be removed. If people go and vote anyways it will just clutter it up!

  • Phil Sturgeon

    This explains where all of the random votes were coming from recently! Please remove that as voting is only meant for voting members. See php-fig.org for more info on who they are and how membership works.

    • Anonymous

      Removing, sorry about that.

  • http://metalmatze.de/ MetalMatze

    Great article! Thanks. Just wondering if I could already use PSR-4 with composer. Is it stable supported?