What Is Autoloading; How to Use Spl_Autoload, _Autoload and Spl_Autoload_Register

What is Autoloading; How do you use spl_autoload, __autoload and spl_autoload_register?

spl_autoload_register() allows you to register multiple functions (or static methods from your own Autoload class) that PHP will put into a stack/queue and call sequentially when a "new Class" is declared.

So for example:

spl_autoload_register('myAutoloader');

function myAutoloader($className)
{
$path = '/path/to/class/';

include $path.$className.'.php';
}

//-------------------------------------

$myClass = new MyClass();

In the example above, "MyClass" is the name of the class that you are trying to instantiate, PHP passes this name as a string to spl_autoload_register(), which allows you to pick up the variable and use it to "include" the appropriate class/file. As a result you don't specifically need to include that class via an include/require statement...

Just simply call the class you want to instantiate like in the example above, and since you registered a function (via spl_autoload_register()) of your own that will figure out where all your class are located, PHP will use that function.

The benefit of using spl_autoload_register() is that unlike __autoload() you don't need to implement an autoload function in every file that you create. spl_autoload_register() also allows you to register multiple autoload functions to speed up autoloading and make it even easier.

Example:

spl_autoload_register('MyAutoloader::ClassLoader');
spl_autoload_register('MyAutoloader::LibraryLoader');
spl_autoload_register('MyAutoloader::HelperLoader');
spl_autoload_register('MyAutoloader::DatabaseLoader');

class MyAutoloader
{
public static function ClassLoader($className)
{
//your loading logic here
}


public static function LibraryLoader($className)
{
//your loading logic here
}

With regards to spl_autoload, the manual states:

This function is intended to be used as a default implementation for __autoload(). If nothing else is specified and spl_autoload_register() is called without any parameters then this functions will be used for any later call to __autoload().

In more practical terms, if all your files are located in a single directory and your application uses not only .php files, but custom configuration files with .inc extensions for example, then one strategy you could use would be to add your directory containing all files to PHP's include path (via set_include_path()).

And since you require your configuration files as well, you would use spl_autoload_extensions() to list the extensions that you want PHP to look for.

Example:

set_include_path(get_include_path().PATH_SEPARATOR.'path/to/my/directory/');
spl_autoload_extensions('.php, .inc');
spl_autoload_register();

Since spl_autoload is the default implementation of the __autoload() magic method, PHP will call spl_autoload when you try and instantiate a new class.

Hope this helps...

How to use spl_autoload_register for multiple diectories in PHP?

For the purpose of keeping individuals who may come across this answer from obtaining out-of-date information I have updated it in regards to the latest PSR autoloading standards. The original answer has been maintained for historical purposes and for those who are only interested in the PSR-0 autoloader.

Updated Answer

The PHP-FIG has officially deprecated the PSR-0 standard in favor of the alternative autoloader, PSR-4. Although the two are similar in some aspects they are also very different in others. (E.g.: the handling of underscores in class names.)

You may be thinking to yourself -- "I use PSR-0 now and it works fine." The truth of the matter is that PSR-0 will still work fine for certain projects. This is especially true when backwards compatibility with a package that doesn't use namespaces is concerned. PSR-0 is still a decent autoloading principle, but it has its own shortcomings.

Of course, if there is one thing that is a constant with programming, it is that code eventually changes and programming techniques continue to evolve. You can do yourself a favor today by preparing yourself for tomorrow. Therefore, if you are just starting a project or are trying to port a project to a newer version of PHP that can use namespaces, you should seriously consider using the PSR-4 autoloader.

It is also worth noting that if you are developing a project that does not use namespaces then PSR-4 does not apply to you. In this case PSR-0 or your own custom autoloader applies.



Original Answer

If you want to go with namespaces in your classes, then the PSR-0 route is a pretty good way to autoload. Basically your namespace represents you directory structure and classes can be loaded based on a convention.

If the PSR-0 method doesn't meet all your needs (or doesn't play nice with existing code) you can still add more functions with spl_autoload_register and PHP will go through them one by one in an attempt to load classes.

Example usage:

First thing is first, if you aren't familiar with namespaces in PHP then you will benefit from checking out the PHP manual on the subject. They can be a bit confusing at first, but their benefits are worth the initial confusion.

So I said that PSR-0 works by associating your namespaces with your directory structure. Let's use your directories for an example. You have in your root folder (wherever it may be) the following:

Project directory:  <- Let's call this directory "MyProject"
Controllers:
Main.php
File.php
About.php
Libs:
Main.php
Front_controller.php
Models:
Index.php
File.php
Login.php
index.php <- Let's say this is your entry point file, this is where you will be autoloading stuff from.

Now let's take a look at your controller Main.php. Two things to keep in mind is that the class name needs to be the name of the file and the namespace for that class is the directory path to that file. So Main.php should look something like this:

<?php

namespace MyProject\Controllers;

class Main {

//Field vars, contructor, methods, etc. all go here.

}

?>

You would do the same thing for your your Login model

<?php

namespace MyProject\Models;

class Login {

//Field vars, contructor, methods, etc. all go here.

}

?>

Now in your index.php file (out in the root directory - MyProject) you would make your call to the spl_autoload_register and give it the PSR-0 autoloader.

spl_autoload_register( function ($className) {
$className = ltrim($className, '\\');
$fileName = '';
$namespace = '';
if ($lastNsPos = strrpos($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;
});

//Now you can make your call to your objects without a bunch of include/require statements

$main = new \MyProject\Controllers\Main(); //Instantiates your 'Main' controller
$login = new \MyProject\Models\Login(); //Instantiates your 'Login' model

Hopefully that helps make better sense of it, and again, if you don't want to use namespaces you can always just keep adding closures into the SPL autoload stack. You can have 10 different autoloaders in there if you want and PHP will go through them one by one (in the order you defined them) using each function to try and load a class. However, a couple convention based autoloaders is a bit cleaner and more of a preferred method. Also keep in mind that the autoloader translates both namespace separators \ and underscores _ as a directory separator. So your Front_controller.php would not autoload as you would expect.

What does everyone mean by: 'spl:_autoload() is default implementation of __autoload()'

Repeating question mentioned earlier: is spl_autoload() internal function?

That's just the "default value" for spl_autoload_register if you don't pass an parameter. You could also call this function standalone, if you want to. The behaviour of spl_autoload could be configured with spl_autoload_extensions and set_include_path.

Internally spl_autoload takes the full qualified class name(fqcn) as the path to look for a class implementation. (Maybe with string replacements for directory seperators). Afterwards, it searches in every element of the class_include_path after the given file.

spl_autoload_extensions(".php");
spl_autoload_register();
$foo = new \foo\Bar();
// now spl_autoload tries to load the file foo/Bar.php inside your class path.

If you need something more complicated, you have to create your own callback for the autoloader. I.e. something like this

spl_autoload_register(function($class) {
$path = 'classes' . DIRECTORY_SEPERATOR;
// dont care about case
$class = strtolower($class);
// replace _ with DIRECTORY_SEPERATOR
$name = str_replace('_', DIRECTORY_SEPERATOR, $class);
// don't care about windows/unix
$name = str_replace('/', DIRECTORY_SEPERATOR, $name);
$file = $path . $name . '.php';
if (file_exists($file)) {
include ($file);
}
});

Note: The example above doesn't care about the value of spl_autoload_extensions or set_include_path.

php spl_autoload_register vs __autoload?

__autoload is generally considered obsolete. It only allows for a single autoloader. Generally you should only use __autoload if you're using a version of PHP without support for spl_autload_register.

spl_autoload_register allows several autoloaders to be registered which will be run through in turn until a matching class/interface/trait is found and loaded, or until all autoloading options have been exhausted. This means that if you're using framework code or other third party libraries that implement their own autoloaders you don't have to worry about yours causing conflicts.

UPDATE:

__autoload is now officially deprecated as of PHP 7.2.0, which means it's now on the chopping block. If you want your code to be compatible with future versions of PHP you definitely should not use __autoload

How to use spl_autoload() instead of __autoload()

You need to register autoload functions with spl_autoload_register. You need to provide a "callable". The nicest way of doing this, from 5.3 onwards, is with an anonymous function:

spl_autoload_register(function($class) {
include 'classes/' . $class . '.class.php';
});

The principal advantage of this against __autoload is of course that you can call spl_autoload_register multiple times, whereas __autoload (like any function) can only be defined once. If you have modular code, this would be a significant drawback.


2018 update to this: there shouldn't really be that many occasions when you need to roll your own autoloader. There is a widely accepted standard (called PSR-4) and several conforming implementations. The obvious way of doing this is using Composer.

How to use spl_autoload_register?

You can't put the code there. You should add the SPL register after your class. If you wanted to register a function inside the Manage class you could do:

class Manage {
public static function autoload($class) {
include $class . '.class.php';
}
}

spl_autoload_register(array('Manage', 'autoload'));

However, as you demonstrated you can use an anonymous function. You don't even need a class, so you can just do:

spl_autoload_register(function($class) {
include $class . '.class.php';
});

Either way, the function you specify is added to a pool of functions that are responsible for autoloading. Your function is appended to this list (so if there were any in the list already, yours will be last). With this, when you do something like this:

UnloadedClass::someFunc('stuff');

PHP will realize that UnloadedClass hasn't been declared yet. It will then iterate through the SPL autoload function list. It will call each function with one argument: 'UnloadedClass'. Then after each function is called, it checks if the class exists yet. If it doesn't it continues until it reaches the end of the list. If the class is never loaded, you will get a fatal error telling you that the class doesn't exist.



Related Topics



Leave a reply



Submit