SunshinePHP Developer Conference 2015

spl_autoload_register

(PHP 5 >= 5.1.2)

spl_autoload_registerثبت توابع داده شده به عنوان پیاده‌سازی __autoload()

Description

bool spl_autoload_register ([ callback $autoload_function [, bool $throw = true [, bool $prepend = false ]]] )

ثبت تابع با استفاده از پشته __autoload فراهم شده spl. اگر پشته فعال نشده باشد فعال خواهد شد.

اگر کد شما تابع __autoload داشته باشد این تابع باید به صورت صریح در پشته __autoload ثبت شود. این کار برای جایگزینی موثر کاشه موتور توسط spl_autoload_register() برای تابع __autoload به کمک spl_autoload() یا spl_autoload_call() است.

اگر باید جندین تابع autoload وجود داشته باشد spl_autoload_register() این امکان را فراهم می‌:ند. به شکل موثری صف توابع autoload ساخته می‌شود و به ترتیب تعریف آنها اجرا خواهد شد . به صورت دیگر __autoload() تنها یکبار تعریف می‌شود.

Parameters

autoload_function

تابع autoload برای ثبت. اگر پارامتر فراهم نشده باشد پیاده ‌سازی پیش‌فرض spl_autoload() ثبت خواهد شد.

throw

این پارامتر ایجاد استثنا توسط spl_autoload_register() در هنگام خطا را مشخص می‌کند.

prepend

اگر درست باشد spl_autoload_register() autoloader را در پشته autoload به صورت پیش الصاق می‌کند .

Return Values

Returns TRUE on success or FALSE on failure.

Changelog

Version Description
5.3.0 پشتیبانی از فضای نام اضافه شد.
5.3.0 پارامتر prepend اضافه شد.

Examples

Example #1 مثال spl_autoload_register()

<?php

namespace Foobar;

class 
Foo {
    static public function 
test($name) {
        print 
'[['$name .']]';
    }
}

spl_autoload_register(__NAMESPACE__ .'\Foo::test'); // As of PHP 5.3.0

new InexistentClass;

?>

The above example will output something similar to:

[[Foobar\InexistentClass]]
Fatal error: Class 'Foobar\InexistentClass' not found in ...

add a note add a note

User Contributed Notes 18 notes

up
75
a dot schaffhirt at sedna-soft dot de
5 years ago
Good news for PHP 5.3 users with namespaced classes:

When you create a subfolder structure matching the namespaces of the containing classes, you will never even have to define an autoloader.

<?php
    spl_autoload_extensions
(".php"); // comma-separated list
   
spl_autoload_register();
?>

It is recommended to use only one extension for all classes. PHP (more exactly spl_autoload) does the rest for you and is even quicker than a semantically equal self-defined autoload function like this one:

<?php
   
function my_autoload ($pClassName) {
        include(
__DIR__ . "/" . $pClassName . ".php");
    }
   
spl_autoload_register("my_autoload");
?>

I compared them with the following setting: There are 10 folders, each having 10 subfolders, each having 10 subfolders, each containing 10 classes.

To load and instantiate these 1000 classes (parameterless no-action constructor), the user-definded autoload function approach took 50ms longer in average than the spl_autoload function in a series of 10 command-line calls for each approach.

I made this benchmark to ensure that I don't recommend something that could be called "nice, but slow" later.

Best regards,
up
20
(delphists) at (apollo) dot (lv)
3 years ago
When using spl_autoload_register() with class methods, it might seem that it can use only public methods, though it can use private/protected methods as well, if registered from inside the class:
<?php

   
class ClassAutoloader {
        public function
__construct() {
           
spl_autoload_register(array($this, 'loader'));
        }
        private function
loader($className) {
            echo
'Trying to load ', $className, ' via ', __METHOD__, "()\n";
            include
$className . '.php';
        }
    }

   
$autoloader = new ClassAutoloader();

   
$obj = new Class1();
   
$obj = new Class2();

?>

Output:
--------
Trying to load Class1 via ClassAutoloader::loader()
Class1::__construct()
Trying to load Class2 via ClassAutoloader::loader()
Class2::__construct()
up
8
anthon at piwik dot org
4 years ago
Think twice about throwing an exception from a registered autoloader.

If you have multiple autoloaders registered, and one (or more) throws an exception before a later autoloader loads the class, stacked exceptions are thrown (and must be caught) even though the class was loaded successfully.
up
7
a dot schaffhirt at sedna-soft dot de
1 year ago
What I said here previously is only true on Windows. The built-in default autoloader that is registered when you call spl_autoload_register() without any arguments simply adds the qualified class name plus the registered file extension (.php) to each of the include paths and tries to include that file.

Example (on Windows):

include paths:
- "."
- "d:/projects/phplib"

qualified class name to load:
network\http\rest\Resource

Here's what happens:

PHP tries to load
'.\\network\\http\\rest\\Resource.php'
-> file not found

PHP tries to load
'd:/projects/phplib\\network\\http\\rest\\Resource.php'
-> file found and included

Note the slashes and backslashes in the file path. On Windows this works perfectly, but on a Linux machine, the backslashes won't work and additionally the file names are case-sensitive.

That's why on Linux the quick-and-easy way would be to convert these qualified class names to slashes and to lowercase and pass them to the built-in autoloader like so:

<?php
spl_autoload_register
(
  function (
$pClassName) {
   
spl_autoload(strtolower(str_replace("\\", "/", $pClassName)));
  }
);
?>

But this means, you have to save all your classes with lowercase file names. Otherwise, if you omit the strtolower call, you have to use the class names exactly as specified by the file name, which can be annoying for class names that are defined with non-straightforward case like e. g. XMLHttpRequest.

I prefer the lowercase approach, because it is easier to use and the file name conversion can be done automatically on deploying.
up
2
rayro at gmx dot de
4 years ago
It is never a good idea and a unconscienable concept to create the classes in the autoload function via eval.
It should be a nice feature with these Exception, but i think anyone is able to handle it without this method although. Atm i dont realize for what this is good for...

As i might note, class_exists() will ever define the classes u only want to check for existance, and will therefor ever return true:
<?php
function EvalIsEvil($class) {
  eval(
'class '.$className.'{}');
}
spl_autoload_register('EvalIsEvil');
if (
class_exists($s="IsMyModuleHere")) {
 
// this is no module, but get there with eval()...
 
return new $s();
}
?>
up
1
phil at propcom dot co dot uk
1 year ago
It is important to note that the autoloader will NOT be called if an E_STRICT error triggers the error handler which, in turn, tries to use classes which are not yet loaded.

In this instance, you should manually load classes required by the error handler.
up
7
Anonymous
4 years ago
Be careful using this function on case sensitive file systems.

<?php
spl_autoload_extensions
('.php');
spl_autoload_register();
?>

I develop on OS X and everything was working fine. But when releasing to my linux server, none of my class files were loading. I had to lowercase all my filenames, because calling a class "DatabaseObject" would try including "databaseobject.php", instead of "DatabaseObject.php"

I think i'll go back to using the slower __autoload() function, just so i can keep my class files readable
up
2
harvey dot NO_SPAM dot robin at gmail dot com
7 years ago
This function is smart enough not to add the same loader twice.  This seems to work for all of the different loader formats.  Example:

<?php
class ALoader
{
  static function
load($class) { return true; }
}

function
anotherLoader($class) {
  return
true;
}

$F = new ALoader;

spl_autoload_register(array('ALoader', 'load'));
spl_autoload_register(array('ALoader', 'load'));
spl_autoload_register(array($F, 'load'));
spl_autoload_register('anotherLoader');
spl_autoload_register('anotherLoader');
var_dump(spl_autoload_functions());

/*
* Results on PHP5.2 CLI, linux.
* array(2) {
*  [0]=>
*  array(2) {
*    [0]=>
*    string(7) "ALoader"
*    [1]=>
*    string(4) "load"
*  }
*  [1]=>
*  string(13) "anotherLoader"
* }
*/
?>
up
2
sebastian dot krebs at kingcrunch dot de
4 years ago
It seems, that  spl_autoload tests, if the class exists, after calling every registered loader. So it breaks the chain, if the class exists and will not call the other loaders

<?php
function a ($c) {
  echo
"a\n";
  class
Bla {} // Usually "include 'path/to/file.php';"
}
function
b ($c) {
  echo
"b\n";
}
spl_autoload_register('a');
spl_autoload_register('b');

$c = new Bla();
?>
up
0
florent at mediagonale dot com
7 years ago
If your autoload function is a class method, you can call spl_autoload_register with an array specifying the class and the method to run.

* You can use a static method :
<?php

class MyClass {
  public static function
autoload($className) {
   
// ...
 
}
}

spl_autoload_register(array('MyClass', 'autoload'));
?>

* Or you can use an instance :
<?php
class MyClass {
  public function
autoload($className) {
   
// ...
 
}
}

$instance = new MyClass();
spl_autoload_register(array($instance, 'autoload'));
?>
up
-1
Kurd the Great
1 year ago
if(!defined('BASE_PATH')) {
    define('BASE_PATH', dirname(__FILE__) . '/');
    require BASE_PATH . 'Autoloader.php';
    Autoloader::Register();
}

class Autoloader
{
    public static function Register() {
        return spl_autoload_register(array('Autoloader', 'Load'));
    }

    public static function Load($strObjectName) {
        if(class_exists($strObjectName) === false) {
            return false;
        }

        $strObjectFilePath = BASE_PATH . $strObjectName . '.php';
       
        if((file_exists($strObjectFilePath) === false) || (is_readable($strObjectFilePath) === false)) {
            return false;
        }
       
        require($strObjectFilePath);
    }
}
up
-1
stanlemon at mac dot com
7 years ago
Editorial note: The appropriate PHP bug that requests behavior this function emulates is http://bugs.php.net/bug.php?id=42823 . This function does NOT work if there has been an array($obj, 'nonStaticMethod') registered in the autoload stack--while the autoload will be removed, it will be re-registered incorrectly.

The spl_autoload_register() method registers functions in its stack in the order that spl_autoload_register() was called, and subsequently if you want an autoload function to override previous autoload functions you will either need to unregister the previous ones or change the order of the autoload stack.

For example, say in your default implementation of an autoload function you throw an exception if the class cannot be found, or perhaps a fatal error.  Later on in your code you add a second implementation of an autoload function which will load a library that the previous method would fail on.  This will not call the second autoloader method first, but rather will continue to error out on the first method.

As previously mentioned, you can unregister the existing autoloader that errors out, or you can create a mechanism for unregistering and re-registering the autoloaders in the order you want.

Here is a sample/example of how you might consider re-registering autoloaders so that the newest autoloader is called first, and the oldest last:

<?php

// Editorial notes: Small bug and compatibility fixes
// added to the function

function spl_autoload_preregister( $autoload ) {
   
// No functions currently in the stack.
   
if ( ($funcs = spl_autoload_functions()) === false ) {
       
spl_autoload_register($autoload);
    } else {
       
// Unregister existing autoloaders...
       
$compat =
           
version_compare(PHP_VERSION, '5.1.2', '<=') &&
           
version_compare(PHP_VERSION, '5.1.0', '>=');
        foreach (
$funcs as $func) {
            if (
is_array($func)) {
               
// :TRICKY: There are some compatibility issues and some
                // places where we need to error out
               
$reflector = new ReflectionMethod($func[0], $func[1]);
                if (!
$reflector->isStatic()) {
                    throw new
Exception('
                        This function is not compatible
                        with non-static object methods due to PHP Bug #44144.
                    '
);
                }
               
// Suprisingly, spl_autoload_register supports the
                // Class::staticMethod callback format, although call_user_func doesn't
               
if ($compat) $func = implode('::', $func);
            }
           
spl_autoload_unregister($func);
        }
       
       
// Register the new one, thus putting it at the front of the stack...
       
spl_autoload_register($autoload);
       
       
// Now, go back and re-register all of our old ones.
       
foreach ($funcs as $func) {
           
spl_autoload_register($func);
        }
    }
}

?>

Note: I have not tested this for overhead, so I am not 100% sure what the performance implication of the above example are.
up
-1
hajo-p
9 months ago
if you have a dir-structure like "/abc/def/ghi", your index.php lies in the top directory, but you want to use namespaces starting with "def" or "ghi":

you can switch the namespace root directory of php with e.g. set_include_path(__DIR__ . '/abc') and afterwards define + use your namespaces with the simple spl_autoload_register() function without any arguments supplied.

remember that php handlers "cli" and "cli-server" are special cases.
up
-2
daniel at amnistechnology dot com
2 years ago
Cleverly - and usefully - I have noticed that (on PHP 5.3 at least) these autoloaders "kick in" even when you call a public static method of an as-yet-unloaded all static class.
up
-11
Anonymous
2 years ago
Note that when specifying the third parameter (prepend), the function will fail badly in PHP 5.2
up
-3
sebastian at 34n dot de
1 year ago
You can also use it like this:

> spl_autoload_register ( array( new AutoloaderClass, 'method') );

or in PHP > 5.3:

> spl_autoload_register ( [ new My\Namespace\Autoloader, 'method'] );

On this way you dont have to create a variable, which is used once.
up
-6
ali dot taheri dot m at gmail dot com
1 year ago
I've made a little function that makes and registers a loader that seems to be safe and reliable although I'm not sure but it feels like a good idea to share, it took me some time to come up with it I hope it saves someone some time,

<?php

function Loader($root = "") {
   
$loaderFunction = create_function('$class', 'include  "' . $root . '$class.php";');
   
spl_autoload_register($loaderFunction);
}

?>

if you have a file system exactly like your directory tree this function works perfectly, I haven't tested it on unix, but on windows, the default loader fails when your webpage isn't in the root directory, this makes sure that it won't cause a problem if your webpage is on a subdir too just pass ../ or more drived ../../ as root and it will work like a charm, note that i couldn't use anonymous functions because then the $root variable wouldn't have the same scope as the Loader function, so the function must be created on the fly. this is a good example of this functions usage

your class:
root/classes/support/classic.php
<?php

   
namespace classes/support;

    class
classic {
        
// class def
   
}

?>

root/support/index.php
<?php

Loader
('../');

use
classes/support/classic;

$cls = new classic();
//use $cls
?>

the loader will make a function like this:
<?php

function($class) {
    include 
"../$class.php";
}

//when and when the class is needed this will run the script which is indeed what we need:

include '../classes/support/classic.php';

?>

hope this helps folks;
up
-3
nmmm at nmmm dot nu
4 months ago
spl_autoload_register() can be used with include_path.

suppose in current directory we have directory "a", and inside there is directory "test" and inside is test.php :

<?
namespace test;
class test{
        function __construct(){
                echo "Test created\n";
        }
}
?>

then we can use following code to load the class:
<?
ini_set("include_path", "./a/");

spl_autoload_register();

$t = new \test\test();
?>
To Top