SPL 函数
在线手册:中文 英文
PHP手册

spl_autoload_register

(PHP 5 >= 5.1.2)

spl_autoload_register注册__autoload()函数

说明

bool spl_autoload_register ([ callback $autoload_function ] )

将函数注册到SPL __autoload函数栈中。如果该栈中的函数尚未激活,则激活它们。

如果在你的程序中已经实现了__autoload函数,它必须显式注册到__autoload栈中。因为 spl_autoload_register()函数会将Zend Engine中的__autoload函数取代为spl_autoload()或spl_autoload_call()。

参数

autoload_function

欲注册的自动装载函数。如果没有提供任何参数,则自动注册autoload的默认实现函数spl_autoload()

返回值

成功时返回 TRUE, 或者在失败时返回 FALSE.

更新日志

版本 说明
5.3.0 Namespaces support was introduced.
5.3.0 The prepend parameter was added.

范例

Example #1 spl_autoload_register() example

<?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;

?>

以上例程的输出类似于:

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

参见


SPL 函数
在线手册:中文 英文
PHP手册
PHP手册 - N: 注册__autoload()函数

用户评论:

Anonymous (04-Feb-2012 12:52)

Note that when specifying the third parameter (prepend), the function will fail badly in PHP 5.2

(delphists) at (apollo) dot (lv) (01-Feb-2011 09:57)

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()

anthon at piwik dot org (05-Jul-2010 05:02)

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.

sebastian dot krebs at kingcrunch dot de (24-Mar-2010 06:54)

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();
?>

Anonymous (17-Mar-2010 04:30)

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

rayro at gmx dot de (04-Jan-2010 11:14)

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();
}
?>

a dot schaffhirt at sedna-soft dot de (28-Jul-2009 03:05)

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,

djames at dealerspan dot com (15-May-2009 05:39)

This behaves more like a QUEUE than a STACK, since the registry is accessed in FIFO order. The autoloaders are attempted in the order they are defined.

mailinglist dot php at hydras-world dot com (27-Jun-2008 12:07)

The automatic generation of classes can be further improved to cater for files that don't actually contain the class they were supposed to contain:

<?php

// code to set include_path...

class AutoloadException extends Exception { }

class
AutoloadClass {

    public static function
autoload($sClassName) {

        @include_once(
$sClassName . '.class.php');

       
// does the class requested actually exist now?
       
if (class_exists($sClassName)) {
           
// yes, we're done
           
return;
        }
       
       
// no, create a new one!
       
eval("class $sClassName {
            function __construct() {
                throw new AutoloadException('Class
$sClassName not found');
            }

            static function __callstatic(\$m, \$args) {
                throw new AutoloadException('Class
$sClassName not found');
            }
        }"
);
    }
}

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

?>

You might be able to expand the example above to automatically generate interfaces too...

Enjoy!

DominicC

stanlemon at mac dot com (28-Sep-2007 06:20)

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.

harvey dot NO_SPAM dot robin at gmail dot com (10-Feb-2007 01:54)

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"
 * }
 */
?>

florent at mediagonale dot com (14-Nov-2006 09:19)

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'));
?>