Invenzzia » Resources / Articles / Efficient autoloaders for PHP / Usage

3. Usage

Open Power Autoloader provides universal class loaders that can handle every PHP project that follows the PSR-0 naming convention, for example Doctrine 2, Symfony 2 or Zend Framework 2. Any number of libraries can be handled by a single autoloader instance. The autoloader setup is very simple. Below, we can see a sample configuration for GenericLoader:

require('../src/Opl/Autoloader/GenericLoader.php');
$loader = new Opl\Autoloader\GenericLoader('../src/');
$loader->addNamespace('Opl');
$loader->addNamespace('Symfony');
$loader->addNamespace('Doctrine');
$loader->addNamespace('Application', '../app/');
$loader->register();

All we have to do is to add all the namespaces we want to handle and define paths to their file locations (if they are different than the default one). Optionally, we can also choose the file extension as the third argument of addNamespace() method. By default, the autoloader assumes that the projects use namespaces, but it can be also reconfigured to handle the legacy code written for PHP 5.2:

<?php
require('../src/Opl/Autoloader/GenericLoader.php');
$loader = new Opl\Autoloader\GenericLoader('../src/');
$loader->addNamespace('Opl');
$loader->addNamespace('Symfony');
$loader->addNamespace('Doctrine');
$loader->addNamespace('Application', '../app/');
$loader->register();
 
$legacyLoader = new Opl\Autoloader\GenericLoader('../src/', '_');
$legacyLoader->addNamespace('Opt');
$legacyLoader->addNamespace('Zend');
$legacyLoader->register();

The second argument of the constructor allows us to select the namespace separator, which is set to \ by default. By replacing it with an underscore, we can handle older code, such as Zend Framework 1.x or Open Power Template 2.1.

For bigger websites, their production environment needs a faster autoloader. When we install the application on the production server, we can change the autoloader to ClassMapLoader which uses a precomputed class map loaded into the memory:

<?php
require('../src/Opl/Autoloader/ClassMapLoader.php');
$loader = new Opl\Autoloader\ClassMapLoader('../src/', '../data/classMap.txt');
$loader->addNamespace('Opl');
$loader->addNamespace('Symfony');
$loader->addNamespace('Doctrine');
$loader->addNamespace('Opt');
$loader->addNamespace('Zend');
$loader->addNamespace('Application', '../app/');
$loader->register();

Notice that this autoloader sees no difference between the libraries that do use PHP 5.3 namespaces and the libraries that do not. Everything we need is stored in a map, so we do not have to worry about it here. As a second argument of the constructor, we must provide the path to the class map file, but how do we generate it? For this task, we must use ClassMapBuilder. It is a directory scanner that tokenizes each encountered PHP file and scans its source for namespace, class and interface definitions. A single file must contain at most one class or interface in order to make it work properly. An extra support for PHP 5.4 traits, which are also the subject of autoloading, is already being implemented.

<?php
require('../src/Opl/Autoloader/ClassMapBuilder.php');
$builder = new Opl\Autoloader\ClassMapBuilder();
$builder->addNamespace('Opl', '../src/');
$builder->addNamespace('Opt', '../src/');
$builder->addNamespace('Symfony', '../src/');
$builder->addNamespace('Doctrine', '../src/');
$builder->addNamespace('Zend', '../src/');
$builder->addNamespace('Application', '../app/');
 
file_put_contents('../data/classMap.txt', serialize($builder->getMap()));

Every call to addNamespace() runs the directory scanner that collects the information about the PHP files. If the scanner encounters a class that is already defined in the map, it overwrites the previous entry. Finally, we must serialize the complete map and save it to a file. This process can be automated, if we use the Symfony 2 Console interface. Then all we have to do is to install the provided command within the interface:

$cli->addCommands(array(
    new \Opl\Autoloader\Command\ClassMapBuild(),
));

Now we can create a builder configuration file:

[config]
outputFile = "./data/classMap.txt"
extension = ".php"
 
[namespaces]
Opl = "./src/"
Opt = "./src/"
Symfony = "./src/"
Zend = "./src/"
Doctrine = "./src/"
Application = "./app/"

And build the map:

$ php cli.php opl:autoloader:build-class-map ./data/classMap.ini