Rectangle
class. Before you can create an instance of the object elsewhere in your code, you first need to pull in the Rectangle.php
file, perhaps by writing something like this:
<?php
require "Rectangle.php";
$rect = new Rectangle(42, 25);
Normally we put each class’ definition in its own file for better organization, and so you need to require/include each of the class files you want to use. If there are only a few files then it isn’t too much of a problem, but oftentimes that’s not the case. It can be very cumbersome to load a large library including all of its dependencies like this.
In this article I’ll walk you through the “history of autoloading,” from the older to the current PSR-0 standard autoloader approach found in many PHP frameworks such as Lithium, Symfony, Zend, etc. Then I will introduce you to the ClassLoader component from the Symfony2 project for PHP 5.3 which follows the PSR-0 standard.
Warning: Most of the code samples in the beginning of this article demonstrate deprecated approaches. It would be unwise to use them in production. I recommend you use one of the PSR-0 standard autoloaders instead.
Autoloading in the “Olden Days”
PHP 5 introduced the magic function__autoload()
which is automatically called when your code references a class or interface that hasn’t been loaded yet. This provides the runtime one last chance to load the definition before PHP fails with an error.
Here’s an example of an extremely basic __autoload()
implementation:
<?php
function __autoload($className) {
$filename = $className . ".php";
if (is_readable($filename)) {
require $filename;
}
}
It’s a good idea to make sure a file exists before you try to include it, but sometimes the file may be there but will not have sufficient read permissions so it’s better to use is_readable()
over file_exists()
which will for test both conditions.
The major drawback to the __autoload()
function is that you can only provide one autoloader with it. PHP 5.1.2 introduced spl_autoload()
which allows you to register multiple autoloader functions, and in the future the __autoload()
function will be deprecated.
The introduction of spl_autoload_register()
gave programmers the ability to create an autoload chain, a series of functions that can be called to try and load a class or interface. For example:
<?php
function autoloadModel($className) {
$filename = "models/" . $className . ".php";
if (is_readable($filename)) {
require $filename;
}
}
function autoloadController($className) {
$filename = "controllers/" . $className . ".php";
if (is_readable($filename)) {
require $filename;
}
}
spl_autoload_register("autoloadModel");
spl_autoload_register("autoloadController");
Generally the functions are called in the order they’re registered, but the order can also be affected by additional arguments passed to spl_autoload_register()
.
It’s important to remember that once a function has been registered with spl_autoload_register()
, the __autoload()
function will no longer be called. If you have an __autoload()
function you want to run as part of your autoloader chain, then you’ll have to register it with spl_autoload_register()
.
Of course, the implementations of the autoloading functions I’ve shown this far have been rather simple. Real-world autoloaders are more complex.
Before real namespace support was introduced in PHP 5.3, developers devised their own approaches to prevent naming collisions. The PEAR Coding Standard used underscores to prefix class names with their directory path; the class Zend_Translate
for example would be defined in the file Zend/Translate.php
. The autoloader needed to replace the underscores with directory separators to locate the definition.
Also, different developers adopted different conventions when it came to naming their class files, for example the files might end in .php
, .class.php
, .inc
, etc. Some libraries may be installed in different paths as well. The loader needed to look in various places for them, so now the loader begins to look like this:
<?php
function __autoload($className) {
$extensions = array(".php", ".class.php", ".inc");
$paths = explode(PATH_SEPARATOR, get_include_path());
$className = str_replace("_" , DIRECTORY_SEPARATOR, $className);
foreach ($paths as $path) {
$filename = $path . DIRECTORY_SEPARATOR . $className;
foreach ($extensions as $ext) {
if (is_readable($filename . $ext)) {
require_once $filename . $ext;
break;
}
}
}
}
Autoloading is a useful idea, but was an idea that desperately needed some standardization.
PSR-0 Standard
After PHP 5.3’s introduction of true namespace support, a group of people from the PHP community decided to create the PHP Standards Working Group in 2009 (later renamed to the Framework Interoperatability Group) and establish the PSR-0 standard which outlines various practices and constraints that must be followed for autoloader interoperability. Below are the requirements for PSR-0 compliance:- A fully-qualified namespace and class must have the following structure
<Vendor Name>(<Namespace>)*<Class Name>
. - Each namespace must have a top-level namespace (“Vendor Name”).
- Each namespace can have as many sub-namespaces as it wishes.
- Each namespace separator is converted to a DIRECTORY_SEPARATOR when loading from the file system.
- Each underscore in the class name is converted to a
DIRECTORY_SEPARATOR
. The underscore has no special meaning in the namespace. - The fully-qualified namespace and class is suffixed with
.php
when loading from the file system. - Alphabetic characters in vendor names, namespaces, and class names may be of any combination of lower case and upper case.
<?php
namespace VendorPackage;
class Example
{
}
Thus, the class definition for DoctrineCommonConnections
would be found at /path/to/project/lib/Doctrine/Common/Connections.php
, and SymfonyCoreRequest
at /path/to/project/lib/Symfony/Core/Request.php
. The PSR-0 standard does not mandate what the base /path/to/project/lib
portion of the path is, and conforming autoloaders offer different methods for its resolution. Some will allow you to register the directory, some will search PHP’s include_path
, and some offer you both. Below is an example taken from the accepted PSR-0 standard.
<?php
function autoload($className)
{
$className = ltrim($className, '\');
$fileName = '';
$namespace = '';
if ($lastNsPos = strripos($className, '\')) {
$namespace = substr($className, 0, $lastNsPos);
$className = substr($className, $lastNsPos + 1);
$fileName = str_replace('\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
}
$fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
require $fileName;
}
This gist by Jonathan Wage is a sample SplClassLoader
implementation that can load your classes if you follow the autoloader interoperability standards. It is the current recommended way to load PHP 5.3 classes that follow these standards.
You can use any one of the PSR-0 compliant autoloaders from frameworks such as Symfony, Pear2, AuraPHP (which is for PHP 5.4+), etc. and adhere to the rules above with your own code to take advantage of autoloading without the uncertainties I discussed previously.
Using Symfony’s Autoloader
The Symfony2 project is a component-based framework for PHP 5.3 and greater which you can use as a component library or as a full-stack framework. You can download Symfony’s Autoloader, the ClassLoader component, via different means — pear.symfony.com, packagist, or from GitHub. Here’s the directory structure of Symfony’s ClassLoader component: Using the component then looks like this:<?php
require_once "/path/to/Symfony/Component/ClassLoader/UniversalClassLoader.php";
use Symfony\Component\ClassLoader\UniversalClassLoader;
$loader = new UniversalClassLoader();
$loader->registerNamespace("Symfony\Component" => "/path/to/symfony/components");
$loader->registerNamespace("Monolog" => "path/to/monolog/src/");
$loader->registerPrefix("Zend_", "path/to/zend/library");
$loader->register();
The registerNamespace()
method is used to inform the autoloader where the given namespace’s base directory maps to on the file system and accepts a namespace as its first argument and path as its second value. You can also register multiple namespaces in a single call with the registerNamespaces()
method.
<?php
$loader->registerNamespaces(array(
"Symfony\Component" => "/path/to/symfony/components",
"Monolog' => "path/to/monolog/src"));
The registerPrefix()
method is used to register pseudo-namespaces which was used by Pear, Zend, and other libraries and frameworks before real namespace support was implemented in PHP as we have already covered above. You can also register mulitple ones with the registerPrefixes()
method and passing it as an associative array.
<?php
$loader->registerPrefixes(array(
"Zend_" => "/path/to/zend/library",
"Twig_" => "path/to/twig/library"));
If you are using the Alternative PHP Cache (APC), a free and open source opcode cache for PHP, then you can may want to consider using the ApcUniversalClassLoader
class. The ApcUniversalClassLoader
extends the UniversalClassLoader
but uses apc_store()
and apc_fetch()
to store lookup information in APC’s cache. The standard UniversalClassLoader
will of course work with APC, but the additional behavior offered by the ApcUniversalClassLoader
class afford extra performance benefit.
<?php
require_once "path/to/Symfony/Component/ClassLoader/UniversalClassLoader.php";
require_once "path/to/Symfony/Component/ClassLoader/ApcUniversalClassLoader.php";
use Symfony\Component\ClassLoader\ApcUniversalClassLoader;
$loader = new ApcUniversalClassLoader("apc.prefix.");
The ApcUniversalClassLoader
accepts a prefix with its constructor. For more information on APC, I suggest reading the APC documentation.
Summary
In this article we have discussed autoloading, from its early days to the current PSR-0 standard which has become widely adopted across many PHP frameworks. Recently, David Coallier tried to push theSplClassloader
class into PHP 5.4 to offer native PSR-0 compliant autoloading functionality, but for various reasons it didn’t happen. Maybe in the future we will see it added. (See the C extension at gist.github.com/1310352.)
Now the current hot discussion in the working group is focused on caching. If it’s something you’d like to be part of, feel free to join the discussion!
Image via Matyas Szabo / Shutterstock
And if you enjoyed reading this post, you’ll love Learnable; the place to learn fresh skills and techniques from the masters. Members get instant access to all of SitePoint’s ebooks and interactive online courses, like Jump Start PHP.
Comments on this article are closed. Have a question about PHP? Why not ask it on our forums?
Frequently Asked Questions (FAQs) about Autoloading and the PSR-0 Standard
What is the PSR-0 standard in PHP?
The PSR-0 standard is a specification in PHP that provides a standard file, class and namespace convention to allow plug-and-play code. In simpler terms, it’s a set of rules that developers follow to standardize and manage the way classes and files are loaded in PHP. This standard was accepted for use in 2009 and has been a significant part of PHP development since then.
How does autoloading work in PHP?
Autoloading in PHP is a feature that automatically loads classes or files when they are needed, rather than having to include them manually. When a class is referenced in the code and it’s not found, PHP automatically calls a special function __autoload(), which you can define to include the class file for you. This helps to reduce the amount of code needed and makes the code cleaner and easier to manage.
What is the difference between PSR-0 and PSR-4?
PSR-0 and PSR-4 are both autoloading standards in PHP, but they have some differences. PSR-0 requires that each namespace must have a top-level namespace (“Vendor Name”), and each namespace can have as many sub-namespaces as it wishes. Also, each namespace separator is converted to a DIRECTORY_SEPARATOR when loading from the file system. PSR-4, on the other hand, eliminates the requirement of having to have a top-level namespace and gives more flexibility in terms of folder structure.
How do I implement PSR-0 in my PHP project?
Implementing PSR-0 in your PHP project involves following the standard’s specifications. This includes organizing your classes and namespaces in a certain way, and setting up an autoloader that follows the PSR-0 rules. You can use the spl_autoload_register() function to register your own autoloader.
What are the benefits of using autoloading in PHP?
Autoloading in PHP provides several benefits. It reduces the amount of code you need to write, as you don’t have to manually include each class file. It also makes your code cleaner and easier to manage, as you don’t have to worry about including files in the right order. Autoloading also improves performance, as classes are only loaded when they are actually needed.
Can I use autoloading with functions, or just with classes?
Autoloading in PHP is primarily designed for use with classes. When a class is referenced and it’s not found, PHP automatically calls the __autoload() function. However, you can use a similar concept with functions by using a function library and a function loader. This is not as common as class autoloading, and it’s not part of the PSR standards.
What is the spl_autoload_register() function?
The spl_autoload_register() function in PHP is a function that you can use to register multiple autoloaders, and it can be used to create a queue of autoloaders in a way that they will be called in the order they were defined. This can be useful in larger projects where you might have classes in different locations.
How do I use namespaces with autoloading?
When using autoloading with namespaces in PHP, you need to follow the PSR-0 or PSR-4 standards. These standards define how to convert a namespace to a file path. Essentially, each namespace separator is converted to a directory separator, and each underscore in the class name is converted to a directory separator.
What is the __autoload() function?
The __autoload() function in PHP is a magic function that is automatically called when a class is referenced and not found. You can define this function to include the class file for you. This function is deprecated as of PHP 7.2.0, and it’s recommended to use spl_autoload_register() instead.
Can I use autoloading with PHP frameworks?
Yes, you can use autoloading with PHP frameworks. In fact, most modern PHP frameworks use autoloading extensively to load classes automatically. They usually follow the PSR-0 or PSR-4 standards for autoloading. This makes it easier to manage and organize your code in a large project.
Hari K T is a Freelance LAMP developer/consultant, open-source contributor auraphp and speaker.