PHP Classes and Objects Autoloading


Example

Nobody wants to require or include every time a class or inheritance is used. Because it can be painful and is easy to forget, PHP is offering so called autoloading. If you are already using Composer, read about autoloading using Composer.

What exactly is autoloading?

The name basically says it all. You do not have to get the file where the requested class is stored in, but PHP automatically loads it.

How can I do this in basic PHP without third party code?

There is the function __autoload, but it is considered better practice to use spl_autoload_register. These functions will be considered by PHP every time a class is not defined within the given space. So adding autoload to an existing project is no problem, as defined classes (via require i.e.) will work like before. For the sake of preciseness, the following examples will use anonymous functions, if you use PHP < 5.3, you can define the function and pass it's name as argument to spl_autoload_register.

Examples

spl_autoload_register(function ($className) {
    $path = sprintf('%s.php', $className);
    if (file_exists($path)) {
        include $path;
    } else {
        // file not found
    }
});

The code above simply tries to include a filename with the class name and the appended extension ".php" using sprintf. If FooBar needs to be loaded, it looks if FooBar.php exists and if so includes it.

Of course this can be extended to fit the project's individual need. If _ inside a class name is used to group, e.g. User_Post and User_Image both refer to User, both classes can be kept in a folder called "User" like so:

spl_autoload_register(function ($className) {
    //                        replace _ by / or \ (depending on OS)
    $path = sprintf('%s.php', str_replace('_', DIRECTORY_SEPARATOR, $className) );
    if (file_exists($path)) {
        include $path;
    } else {
        // file not found
    }
});

The class User_Post will now be loaded from "User/Post.php", etc.

spl_autoload_register can be tailored to various needs. All your files with classes are named "class.CLASSNAME.php"? No problem. Various nesting (User_Post_Content => "User/Post/Content.php")? No problem either.

If you want a more elaborate autoloading mechanism - and still don't want to include Composer - you can work without adding third party libraries.

spl_autoload_register(function ($className) {
    $path = sprintf('%1$s%2$s%3$s.php',
        // %1$s: get absolute path
        realpath(dirname(__FILE__)),
        // %2$s: / or \ (depending on OS)
        DIRECTORY_SEPARATOR,
        // %3$s: don't wory about caps or not when creating the files
        strtolower(
            // replace _ by / or \ (depending on OS)
            str_replace('_', DIRECTORY_SEPARATOR, $className)
        )
    );

    if (file_exists($path)) {
        include $path;
    } else {
        throw new Exception(
            sprintf('Class with name %1$s not found. Looked in %2$s.',
                $className,
                $path
            )
        );
    }
});

Using autoloaders like this, you can happily write code like this:

require_once './autoload.php'; // where spl_autoload_register is defined

$foo = new Foo_Bar(new Hello_World());

Using classes:

class Foo_Bar extends Foo {}
class Hello_World implements Demo_Classes {}

These examples will be include classes from foo/bar.php, foo.php, hello/world.php and demo/classes.php.