Before we implement a PSR-0 autoloader, we need to pick a directory location in the codebase to hold every class that will ever be used in the codebase. Some projects already have such a location; it may be called includes
, classes
, src
, lib
or something similar.
If a location like that already exists, examine it carefully. Does it have only class files in it, or is it a combination of class files and other kinds of files? If it has anything besides class files in it, or if no such location exists, create a new directory location and call it classes (or some other properly descriptive name).
This directory will be the central location for all classes used throughout the project. Later, we will begin moving classes from their scattered locations in the project to this central location.
Once we have a central directory location for our class files, we need to set up an autoloader to look in that location for classes. We can create the autoloader as a static method, an instance method, an anonymous function, or a regular global function. (Which one we use is not as important as actually doing the autoloading.) Then we will register it with spl_autoload_register()
early in our bootstrap or setup code, before any classes are called.
Perhaps the most straightforward way to implement our new autoloader code is as a global function. Below, we find the autoloader code to use; the function name is prefixed with mlaphp_
to make sure it does not conflict with any existing function names.
setup.php
1 <?php
2 // ... setup code ...
3
4 // define an autoloader function in the global namespace
5 function mlaphp_autoloader($class)
6 {
7 // strip off any leading namespace separator from PHP 5.3
8 $class = ltrim($class, '\\');
9
10 // the eventual file path
11 $subpath = '';
12
13 // is there a PHP 5.3 namespace separator?
14 $pos = strrpos($class, '\\');
15 if ($pos !== false) {
16 // convert namespace separators to directory separators
17 $ns = substr($class, 0, $pos);
18 $subpath = str_replace('\\', DIRECTORY_SEPARATOR, $ns)
19 . DIRECTORY_SEPARATOR;
20 // remove the namespace portion from the final class name portion
21 $class = substr($class, $pos + 1);
22 }
23
24 // convert underscores in the class name to directory separators
25 $subpath .= str_replace('_', DIRECTORY_SEPARATOR, $class);
26
27 // the path to our central class directory location
28 $dir = '/path/to/app/classes';
29
30 // prefix with the central directory location and suffix with .php,
31 // then require it.
32 $file = $dir . DIRECTORY_SEPARATOR . $subpath . '.php';
33 require $file;
34 }
35
36 // register it with SPL
37 spl_autoload_register('mlaphp_autoloader');
38 ?>
Note that the $dir
variable represents an absolute directory as the base path for our central class directory. As an alternative on PHP 5.3 and later, it is perfectly acceptable to use the __DIR__
constant in that variable so the absolute path is no longer hard-coded, but is instead relative to the file where the function is located. For example:
1 <?php 2 // go "up one directory" for the central classes location 3 $dir = dirname(__DIR__) . '/classes'; 4 ?>
If you are stuck on PHP 5.2 for some reason, the __DIR__
constant is not available. You can replace dirname(__DIR__)
with dirname(dirname(__FILE__))
in that case.
If we are using PHP 5.3, we can create the autoloader code as a closure and register it with SPL in a single step:
setup.php
1 <?php
2 // ... setup code ...
3
4 // register an autoloader as an anonymous function
5 spl_autoload_register(function ($class) {
6 // ... the same code as in the global function ...
7 });
8
9 // ... other setup code ...
10 ?>
This is my preferred way of setting up an autoloader. Instead of using a function, we create the autoloader code in a class as an instance method or a static method. I recommend instance methods over static ones, but your situation will dictate which is more appropriate.
First, we create our autoloader class file in our central class directory location. If we are using PHP 5.3 or later, we should use a proper namespace; otherwise, we use underscores as pseudo-namespace separators.
The following is a PHP 5.3 example. Under versions earlier than PHP 5.3, we would omit the namespace
declaration and name the class Mlaphp_Autoloader
. Either way, the file should be in the sub-path Mlaphp/Autoloader.php
:
/path/to/app/classes/Mlaphp/Autoloader.php
1 <?php
2 namespace Mlaphp;
3
4 class Autoloader
5 {
6 // an instance method alternative
7 public function load($class)
8 {
9 // ... the same code as in the global function ...
10 }
11
12 // a static method alternative
13 static public function loadStatic($class)
14 {
15 // ... the same code as in the global function ...
16 }
17 }
18 ?>
Then, in the setup or bootstrap file, require_once
the class file, instantiate it if needed, and register the method with SPL. Note that we use the array-callable format here, where the first array element is either a class name or an object instance, and the second element is the method to call:
setup.php
1 <?php
2 // ... setup code ...
3
4 // require the autoloader class file
5 require_once '/path/to/app/classes/Mlaphp/Autoloader.php';
6
7 // STATIC OPTION: register a static method with SPL
8 spl_autoload_register(array('Mlaphp\Autoloader', 'loadStatic'));
9
10 // INSTANCE OPTION: create the instance and register the method with SPL
11 $autoloader = new \Mlaphp\Autoloader();
12 spl_autoload_register(array($autoloader, 'load'));
13
14 // ... other setup code ...
15 ?>
Please pick either an instance method or a static method, not both. The one is not a fallback for the other.