PHP Autoloader
Autoloading was introduced in PHP 5. Autoloading is a mechanism which requires a class definition 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 classdefinitions 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
- Namespaces
- Index based class search
- optimized file search
- class constructor
- multiple usage
How PHP Autoloader works
The PHP Autoloader searches recursively in defined directories for class 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 dirname(__FILE__) . '/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 dirname(__FILE__) . '/autoloader/Autoloader.php';
$autoloader = new Autoloader(dirname(__FILE__));
$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/ExceptionB.php
<?php
class ExceptionB extends Exception
{
static public function classConstructor()
{
echo __CLASS__, " loaded.\n";
}
}- ./classes/packageB/InterfaceB.php
<?php
echo "InterfaceB loaded.\n";
interface InterfaceB
{
}- ./classes/packageB/ClassB.php
<?php
class ClassB implements InterfaceB
{
static public function classConstructor()
{
echo __CLASS__, " loaded.\n";
}
}- ./classes/ClassA.php
<?php
class ClassA extends ClassB
{
static public function classConstructor()
{
echo __CLASS__, " loaded.\n";
}
}- ./index.php
#!/usr/bin/php
<?php
try {
include dirname(__FILE__) . '/../../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. ClassB loaded. ClassA loaded. object(ClassA)#2 (0) { } object(ClassB)#8 (0) { }