PHP Autoloader

Autoloading was introduced in PHP 5. Autoloading is a mechanism which requires class, interface and trait definitions on demand.

PHP offers two ways to realize this mechanism. You can either implement the function __autoload() or register a callback with spl_autoload_register(). spl_autoload_register() should be prefered over __autoload(), as __autoload() can only be implemented once. spl_autoload_register() can register many Autoloaders. That's important if you're using several libraries with own Autoloaders.

A convenient Autoloader makes these orgy of require_once in each file superfluous. An even more convenient Autoload implementation lets moving of class definitions happen without any additional effort.

As files are required on demand, you don't have to care about unnecessary file operations. Before Autoloading you had to require every possibly used class definition in advance. That led PHP to parse files which are actually never used during runtime, like unreached Type Hints in Catch-Blocks:

<?php

try {
    exit();
    
} catch (
MyException $e) {
    
/* This block will never be reached. Without Autoloading
     * it's necessary to require the definition of MyException. 
     * With Autoloading PHP is able to omit this definition.
     */
    
}

Beside the comfort aspect, there exists the need to declare classes before deserialization. That's especially important if you cannot predict the content of a session. Without an autoloader you have to include every possible class definition or you risk the instantiation of incomplete __PHP_Incomplete_Class objects. Any method call on these objects leed to a fatal error.

PHP Autoloader features

How PHP Autoloader works

The PHP Autoloader searches recursively in defined directories for class, trait and interface definitions. Without any further configuration the directory in which the requiring file resides will be used as default class path.

File names don't need to obey any convention. All files are searched for class definitions. Files which are similar to the class name or end with .php or .inc are preferred. If supported, PHP Tokenizer will be used for reliable class definition discovery.

A found class won't be searched again. The location of its class definition is stored in a PHP Autoloader Index.

After requiring a class definition PHP Autoloader tries to call the optional existing class constructor public static function classConstructor().

PHP Autoloader usage

The PHP Autoloader runs without any further configuration out of the box. To use it there is nothing more to do than require the file autoloader/autoloader.php:

<?php

require __DIR__ '/autoloader/autoloader.php';

This example registers an Autoloader with the class path of the directory which contains that code. You could also register an Autoloader with an arbitrary class path. Following example does that by registering an equivalent Autoloader:

<?php

require __DIR__ '/autoloader/autoloader.php';
$autoloader = new Autoloader(__DIR__);
$autoloader->register();

You may noticed the require instead of require_once. That's because you might use other components which already use this autoloader implementation. So you really need to require the Autoloader again, to make sure all class paths are registered.

PHP Autoloader example application

In the directory autoloader/docs/examples/ exists this example application:

./classes/packageB/ClassB.php
<?php

namespace malkusch\autoloader\example;

class 
ClassB implements InterfaceB
{

    use 
ClassConstructorTrait;



echo 
"ClassB loaded.\n";
./classes/packageB/ClassConstructorTrait.php
<?php

namespace malkusch\autoloader\example;

trait 
ClassConstructorTrait
{
    
    static public function 
classConstructor()
    {
        echo 
"calling class constructor for class "__CLASS__".\n";
    }
    
}

echo 
"ClassConstructorTrait loaded.\n";
./classes/packageB/ExceptionB.php
<?php

namespace malkusch\autoloader\example;

class 
ExceptionB extends Exception
{

    use 
ClassConstructorTrait;

}

echo 
"ExceptionB loaded.\n";
./classes/packageB/InterfaceB.php
<?php

namespace malkusch\autoloader\example;

interface 
InterfaceB
{

}

echo 
"InterfaceB loaded.\n";
./classes/ClassA.php
<?php

namespace malkusch\autoloader\example;

class 
ClassA extends ClassB
{
    
}

echo 
"ClassA loaded.\n";
./index.php
#!/bin/env php
<?php

namespace malkusch\autoloader\example;

try {
    require 
__DIR__ "/../../autoloader.php";

    
$a = new ClassA();
    
$b = new ClassB();

    
var_dump($a$b);

} catch (
ExceptionB $e) {

}

The output of the script index.php shows that the class ExceptionB wasn't required:

InterfaceB loaded. ClassConstructorTrait loaded. ClassB loaded. calling class constructor for class malkusch\autoloader\example\ClassB. ClassA loaded. object(malkusch\autoloader\example\ClassA)#11 (0) { } object(malkusch\autoloader\example\ClassB)#9 (0) { }

Deployable Autoloader

Beside the dynamic autoloader exists a small deployable autoloader. This autoloader must be build by the script autoloader/bin/autoloader-build.php. The script builds an index of all classes and deploys a small autoloader. The deployed autoloader is fast and with one class very compact. You should prefer this autoloader if:

The script explaines itself if you call it without arguments:

autoloader-build.php -c <classpath> {-c <classpath>} [-d <deploypath] [-r] -c, --classpath=CP Search for classes in classpath CP. You can add more classpaths by adding more --classpath options. -d, --deploypath=DP Deploy the generated index and the Autoloader in the path DP. -r, --require Don't use autoloading. All classes of the generated index will be included.

Let's have a look at the upper example project. Below the directory classes/ lie all classes. We want to build an autoloader and deploy it at the directory autoloader/.

autoloader-build.php -c examples/classes -d examples/autoloader

To use the deployed autoloader you have to require it in the index.php: require_once __DIR__ . "/autoloader/autoloader.php";