PHP Doku:: Register given function as __autoload() implementation - function.spl-autoload-register.html

Verlauf / Chronik / History: (1) anzeigen

Sie sind hier:
Doku-StartseitePHP-HandbuchFunktionsreferenzSonstige GrunderweiterungenStandard PHP Library (SPL)SPL Funktionenspl_autoload_register

Ein Service von Reinhard Neidl - Webprogrammierung.

SPL Funktionen

<<spl_autoload_functions

spl_autoload_unregister>>

spl_autoload_register

(PHP 5 >= 5.1.2)

spl_autoload_registerRegister given function as __autoload() implementation

Beschreibung

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

Register a function with the spl provided __autoload stack. If the stack is not yet activated it will be activated.

If your code has an existing __autoload function then this function must be explicitly registered on the __autoload stack. This is because spl_autoload_register() will effectively replace the engine cache for the __autoload function by either spl_autoload() or spl_autoload_call().

If there must be multiple autoload functions, spl_autoload_register() allows for this. It effectively creates a queue of autoload functions, and runs through each of them in the order they are defined. By contrast, __autoload() may only be defined once.

Parameter-Liste

autoload_function

The autoload function being registered. If no parameter is provided, then the default implementation of spl_autoload() will be registered.

throw

This parameter specifies whether spl_autoload_register() should throw exceptions on error.

prepend

If true, spl_autoload_register() will prepend the autoloader on the autoload stack instead of appending it.

Rückgabewerte

Gibt bei Erfolg TRUE zurück. Im Fehlerfall wird FALSE zurückgegeben.

Changelog

Version Beschreibung
5.3.0 Namespaces support was introduced.
5.3.0 The prepend parameter was added.

Beispiele

Beispiel #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;

?>

Das oben gezeigte Beispiel erzeugt eine ähnliche Ausgabe wie:

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


13 BenutzerBeiträge:
- Beiträge aktualisieren...
anthon at piwik dot org
5.07.2010 6: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.03.2010 19: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.03.2010 5: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
4.01.2010 12: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.07.2009 4: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.05.2009 18: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.
Keilioto
2.05.2009 13:49
More simple solution:
<?php
function __autoload($className)
{
    eval(
'class '.$className.'{}');
    throw new
Exception('Class '.$className.' not exists');
}
?>
emailmatthijs at gmail dot com
18.08.2008 15:41
This is my version of making it possible to throw exceptions within autoload functions. I liked the functions which used __construct and __callStatic to throw the exceptions, but I did not want to relay on __callStatic because it only exists since PHP version 5.3.0. I tested all three examples below in PHP version 5.2.6. The class named Test and Test_Interface did both not exists.

<?php
new Test();

Test::test();

class
Test implements Test_Interface {}
?>

In all three cases it succesfully throwed the exception without any fatal errors.

<?php
function __autoload($sClass)
{
    try
    {
        throw new
Exception('It works');
    }
    catch (
Exception $oException)
    {
       
throwAutoloadException($sClass, $oException);
    }
}

function
throwAutoloadException($sClass, Exception $oException)
{
   
// The use of eval is risky, because it could be easily exploited. To prefend
    // that the use of eval in this method could be exploited we make sure that the
    // variable contains only the allowed characters of a class name.
   
if (preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $sClass))
    {
        eval(
'class '.$sClass.'
        {
            static public function throwException()
            {
                throw unserialize(\''
.serialize($oException).'\');
            }
        }
       
        '
.$sClass.'::throwException();');
    }
}
?>
mailinglist dot php at hydras-world dot com
27.06.2008 1: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
webtweakers at gmail dot com
21.02.2008 22:53
For a while I was using the class autoload solution of sandrejev at gmail dot com, 08-Nov-2006 11:23, on this page http://www.php.net/manual/en/language.oop5.autoload.php.

As it appears, this method works fine most of the time, except in two specific cases:

1. It does not handle static classes correctly (also see the note of ostapk, 19-Dec-2007 02:46, same page and the article at onphp (s)he refers to).

2. When you accidentally have a variable in your stack that contains single quotes, PHP will choke with the following cryptic message:

Parse error: parse error, unexpected T_STRING in autoload.inc.php(64) : eval()'d code on line 26

I came up with this solution, which seems to solve these problems:

<?php

// code to set include_path...

class AutoloadException extends Exception { }

class
AutoloadClass {

    public static function
autoload($sClassName) {

       
$bIsExisting = @include_once($sClassName . '.class.php');
        if (
$bIsExisting) return;

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

?>

Now, my application, that indeed uses run-time defined (static) classes that are actually allowed not to exist, runs correctly again. The AutoloadException can be caught to handle this case without stopping code execution with a Fatal Error.
stanlemon at mac dot com
28.09.2007 19: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.02.2007 14: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.11.2006 10: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'));
?>



PHP Powered Diese Seite bei php.net
The PHP manual text and comments are covered by the Creative Commons Attribution 3.0 License © the PHP Documentation Group - Impressum - mail("TO:Reinhard Neidl",...)