PSR-0 and PSR-4 autoloading of classes in PHP

The PHP Framework Interop Group is about interoperability standards between frameworks so that code can be reused between projects. To facilitate this way of working there is “Composer” (a package manager) and “Packagist” (a package repository) made available. The SCM system used by the packages is mainly Git and the code repository resides most of the times on Github. Symfony2 is heavily using this system already. For class autoloading (the most important interoperability problem) the following standards apply:

The following PHP file can be put into the vendor directory (and required by your project) to do autoloading of classes:

class Loader
{
    protected static $parentPath = null;
    protected static $paths = null;
    protected static $nsChar = '\\';
    protected static $initialized = false;

    protected static function initialize()
    {
        if (static::$initialized) return;
        static::$initialized = true;
        static::$parentPath = __FILE__;
        for ($i=substr_count(get_class(), static::$nsChar);$i>=0;$i--) {
            static::$parentPath = dirname(static::$parentPath);
        }
        static::$paths = array();
        static::$files = array(__FILE__);
    }

    public static function register($path,$namespace) {
        if (!static::$initialized) static::initialize();
        static::$paths[$namespace] = trim($path,DIRECTORY_SEPARATOR);
    }

    public static function load($class) {
        if (class_exists($class,false)) return;
        if (!static::$initialized) static::initialize();

        foreach (static::$paths as $namespace => $path) {
            if (!$namespace || $namespace.static::$nsChar === substr($class, 0, strlen($namespace.static::$nsChar))) {

                $fileName = substr($class,strlen($namespace.static::$nsChar)-1);
                $fileName = str_replace(static::$nsChar, DIRECTORY_SEPARATOR, ltrim($fileName,static::$nsChar));
                $fileName = static::$parentPath.DIRECTORY_SEPARATOR.$path.DIRECTORY_SEPARATOR.$fileName.'.php';

                if (file_exists($fileName)) {
                  include $fileName;
                  return true;
                }
            }
        }
        return false;
    }
}

spl_autoload_register(array('Loader', 'load'));

If you clone the guzzle library into “vendor/guzzle” then you can use the snippet below to load the Loader class and register the library. After that you can just use the Guzzle Client class, because the Loader takes care of the autoloading.

require 'vendor/autoload.php';
Loader::register('guzzle','GuzzleHttp');
use GuzzleHttp\Client;
$client = new Client();
// do something with $client

Alternatively, you can also use the autoloading file generated by Composer. I recommend doing this in a production environment. Using Composer allows you to manage your dependencies and automatically update them when new versions are released. This post should show you how the autoloading mechanism works in PHP. It also shows you how to build your own standards compliant autoloading mechanism, something you probably only need when building your own PHP framework.

3 thoughts on “PSR-0 and PSR-4 autoloading of classes in PHP”

  1. if you’re using other include paths (php.ini)
    you could replace if (file_exists($fileName)) {
    with if(stream_resolve_include_path($fileName) !== false) {

    and if you would like a PHP_ERROR replace include with require. (_once)

  2. @Arnold: Thank you for the excellent remarks! I updated the code, it now has static instead of self. I think using stream_resolve_include_path makes sense, but in the code I am already having absolute pathnames. I think in that case it does not make sense, right? Maybe I should rewrite the code to use the include paths.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>