Automatisches Laden von Klassen

Viele Entwickler, die objektorientierte Anwendungen entwickeln, erzeugen für jede Klassendefinition eine eigene PHP-Quelldatei. Eines der größten Ärgernisse ist die Notwendigkeit, am Anfang eines jeden Skripts eine lange Liste von benötigten Include-Anweisungen (eine für jede Klasse) schreiben zu müssen.

Die Funktion spl_autoload_register() registriert eine beliebige Anzahl von Autoladern, die es ermöglichen, dass Klassen und Schnittstellen automatisch geladen werden, wenn sie derzeit nicht definiert sind. Durch das Registrieren von Autoladern erhält PHP einen letzten Versuch, die Klasse oder Schnittstelle zu laden, bevor es unter Ausgabe einer Fehlermeldung scheitert.

Jedes klassenähnliche Konstrukt kann auf die gleiche Weise automatisch geladen werden. Dazu gehören Klassen, Schnittstellen, Traits und Aufzählungen.

Achtung

Vor PHP 8.0.0 war es möglich, __autoload() zu verwenden, um Klassen und Schnittstellen automatisch zu laden. Dies ist jedoch eine weniger flexible Alternative zu spl_autoload_register(). __autoload() ist seit PHP 7.2.0 veraltet und wurde in PHP 8.0.0 entfernt.

Hinweis:

Die Funktion spl_autoload_register() kann mehrfach aufgerufen werden, um mehrere Autoloader zu registrieren. Wenn von einer Autoload-Funktion eine Exception ausgelöst wird, wird dieser Vorgang jedoch unterbrochen und es werden keine weiteren Autoload-Funktionen ausgeführt. Aus diesem Grund wird dringend davon abgeraten, von einer Autoload-Funktion aus eine Exception auszulösen.

Beispiel #1 Autoload-Beispiel

Dieses Beispiel versucht die Klassen MyClass1 und MyClass2 aus den entsprechenden Dateien MyClass1.php und MyClass2.php zu laden.

<?php
spl_autoload_register
(function ($class_name) {
include
$class_name . '.php';
});

$obj = new MyClass1();
$obj2 = new MyClass2();
?>

Beispiel #2 Weiteres Autoload-Beispiel

Dieses Beispiel versucht, das Interface ITest zu laden.

<?php

spl_autoload_register
(function ($name) {
var_dump($name);
});

class
Foo implements ITest {
}

/*
string(5) "ITest"

Fatal error: Interface 'ITest' not found in ...
*/
?>

add a note add a note

User Contributed Notes 40 notes

up
86
jarret dot minkler at gmail dot com
15 years ago
You should not have to use require_once inside the autoloader, as if the class is not found it wouldn't be trying to look for it by using the autoloader.

Just use require(), which will be better on performance as well as it does not have to check if it is unique.
up
14
toi]n[enkayt[attaat]gmaal.com
4 years ago
Autoloading plain functions is not supported by PHP at the time of writing. There is however a simple way to trick the autoloader to do this. The only thing that is needed is that the autoloader finds the searched class (or any other autoloadable piece of code) from the files it goes through and the whole file will be included to the runtime.

Let's say you have a namespaced file for functions you wish to autoload. Simply adding a class of the same name to that file with a single constant property is enough to trigger the autoloader to seek for the file. Autoloading can then be triggered by accessing the constant property.

The constant could be replaced by any static property or method or by default constructor. However, I personally find a constant named 'load' elegant and informative. After all this is a workaround. Another thing to keep in mind is that this introduces an unnecessary class to the runtime. The benefit of this is that there is no need to manually include or require files containing functions by path which in turn makes code maintaining easier. Such behaviour makes it easier to alter the project structure since manual includes need not to be fixed. Only the autoloader needs to be able to locate the moved files which can be automated.

A code file containing functions.
/Some/Namespace/Functions.php
<?php
namespace Some\Namespace;

class
Functions { const load = 1; }

function
a () {
}

function
b () {
}
?>

Triggering autoloading of the file containing functions.
main.php
<?php
\Some\Namespace\Functions::load;

a ();
b ();
?>
up
77
ej at campbell dot name
13 years ago
You don't need exceptions to figure out if a class can be autoloaded. This is much simpler.

<?php
//Define autoloader
function __autoload($className) {
      if (
file_exists($className . '.php')) {
          require_once
$className . '.php';
          return
true;
      }
      return
false;
}

function
canClassBeAutloaded($className) {
      return
class_exists($className);
}
?>
up
46
str at maphpia dot com
7 years ago
This is my autoloader for my PSR-4 clases. I prefer to use composer's autoloader, but this works for legacy projects that can't use composer.

<?php
/**
* Simple autoloader, so we don't need Composer just for this.
*/
class Autoloader
{
    public static function
register()
    {
       
spl_autoload_register(function ($class) {
           
$file = str_replace('\\', DIRECTORY_SEPARATOR, $class).'.php';
            if (
file_exists($file)) {
                require
$file;
                return
true;
            }
            return
false;
        });
    }
}
Autoloader::register();
up
30
james dot dot dot dunmore at gmail dot com
15 years ago
Andrew: 03-Nov-2006 12:26

That seems a bit messy to me, this is a bit neater:
<?php
   
function __autoload($class_name)
    {
       
//class directories
       
$directorys = array(
           
'classes/',
           
'classes/otherclasses/',
           
'classes2/',
           
'module1/classes/'
       
);
       
       
//for each directory
       
foreach($directorys as $directory)
        {
           
//see if the file exsists
           
if(file_exists($directory.$class_name . '.php'))
            {
                require_once(
$directory.$class_name . '.php');
               
//only require the class once, so quit after to save effort (if you got more, then name them something else
               
return;
            }           
        }
    }
up
8
jbarker at erepublic dot com
15 years ago
In a subclass, I was trying to call an overridden parent method with an arbitrary number of arguments:

<?php
call_user_func_array
(array('parent', 'someNonStaticMethod'), $args);
?>

It turns out this triggers an E_STRICT level warning. So I changed to this:

<?php
call_user_func_array
(array($this, 'parent::someNonStaticMethod'), $args);
?>

This doesn't trigger any warnings, but it has the undesirable (if not downright buggy) effect of calling my __autoload() function with the argument 'parent'. I had to modify __autoload() to handle this special situation:

<?php
function __autoload($cls)
{
    if (
'parent' != $cls)
    {
        require(
"class.$cls.php");
    }
}
?>

Tested on Linux with PHP 5.1.6 and 5.2.5.
up
7
Anonymous
14 years ago
It's worth to mention, if your operating system is case-sensitive you need to name your file with same case as in source code eg. MyClass.php instead of myclass.php
up
8
rojoca
16 years ago
Be careful when using eval (as always) in __autoload. The following:

<?php

echo 'Start->';

function
__autoload($class) {
    eval(
'class ' . $class . ' {};');
}

$class = 'Class1{}; echo "uh oh"; class Class2';

$obj = new $class;

echo
'end';
?>

outputs:

Start->uh oh

You can use preg_replace to clean up $class to prevent executing abitrary code but in this case you won't be able to throw a catchable exception and your script will end with a fatal error.
up
11
Chris Corbyn (chris AT w3style.co.uk)
17 years ago
I'm sure this is needed by more than me.

My objective was to allow __autoload() to be easily extended in complex systems/frameworks where specific libraries etc may need loading differently but you don't want to hard-code little adjustments into your working __autoload() to allow this to happen.

Using a ServiceLocator object with some static methods and properties to allow loosely coupled locators to be attached to it you can swap/change and add to the functionality of your __autoload() at runtime.

The core stuff:
<?php

/**
* Defines the methods any actual locators must implement
* @package ServiceLocator
* @author Chris Corbyn
*/
interface Locator
{
   
/**
     * Inform of whether or not the given class can be found
     * @param string class
     * @return bool
     */
   
public function canLocate($class);
   
/**
     * Get the path to the class
     * @param string class
     * @return string
     */
   
public function getPath($class);
}

/**
* The main service locator.
* Uses loosely coupled locators in order to operate
* @package ServiceLocator
* @author Chris Corbyn
*/
class ServiceLocator
{
   
/**
     * Contains any attached service locators
     * @var array Locator
     */
   
protected static $locators = array();
   
   
/**
     * Attach a new type of locator
     * @param object Locator
     * @param string key
     */
   
public static function attachLocator(Locator $locator, $key)
    {
       
self::$locators[$key] = $locator;
    }
   
/**
     * Remove a locator that's been added
     * @param string key
     * @return bool
     */
   
public static function dropLocator($key)
    {
        if (
self::isActiveLocator($key))
        {
            unset(
self::$locators[$key]);
            return
true;
        }
        else return
false;
    }
   
/**
     * Check if a locator is currently loaded
     * @param string key
     * @return bool
     */
   
public static function isActiveLocator($key)
    {
        return
array_key_exists($key, self::$locators);
    }
   
/**
     * Load in the required service by asking all service locators
     * @param string class
     */
   
public function load($class)
    {
        foreach (
self::$locators as $key => $obj)
        {
            if (
$obj->canLocate($class))
            {
                require_once
$obj->getPath($class);
                if (
class_exists($class)) return;
            }
        }
    }
}

/**
* PHPs default __autload
* Grabs an instance of ServiceLocator then runs it
* @package ServiceLocator
* @author Chris Corbyn
* @param string class
*/
function __autoload($class)
{
   
$locator = new ServiceLocator();
   
$locator->load($class);
}

?>

An example Use Case:
<?php

require 'ServiceLocator.php';

//Define some sort of service locator to attach...
class PearLocator implements Locator
{
    protected
$base = '.';
   
    public function
__construct($directory='.')
    {
       
$this->base = (string) $directory;
    }
   
    public function
canLocate($class)
    {
       
$path = $this->getPath($class);
        if (
file_exists($path)) return true;
        else return
false;
    }
   
    public function
getPath($class)
    {
        return
$this->base . '/' . str_replace('_', '/', $class) . '.php';
    }
}

// ... attach it ...
ServiceLocator::attachLocator(new PearLocator(), 'PEAR');

// ... and code away....
$foo = new Foo_Test();

?>
up
8
peter dot gooman at gmail dot com
16 years ago
Before you start using __autload, remember that it holds no scope/namespace. This means that if you are depending on third party applications and they have an autoload function defined and so do you, your application will error.

To remedy this, everyone should look at the spl_autoload functions, eg: spl_autoload_register. This function allows more than one custom functions to be called through the default spl_autoload (default __autoload) handler.
up
4
petyo()architect . bg
19 years ago
The following function may be useful if you want to simulate namespaces and autoloading behavior:

define ("CLASS_ROOT", '/classes/');
function __autoload ($className)
{
    require_once CLASS_ROOT.str_replace('_', '/', $className).'.class.php';
}

Then you will just have to use the folder structure and name the classes accordingly. If you want to have a class named Page, which will be in the pseudo namespace System.Web.UI, create a directory named System in /classes, then create Web, then UI, then name the class System_Web_UI_Page. Kind of long to type if you don't have autocomplete, but at least you will not have to manage the loading of all the classes' definitions.
up
15
fka at fatihkadirakin dot com
13 years ago
Or you can use this, without using any "require/include":

<?php
class autoloader {

    public static
$loader;

    public static function
init()
    {
        if (
self::$loader == NULL)
           
self::$loader = new self();

        return
self::$loader;
    }

    public function
__construct()
    {
       
spl_autoload_register(array($this,'model'));
       
spl_autoload_register(array($this,'helper'));
       
spl_autoload_register(array($this,'controller'));
       
spl_autoload_register(array($this,'library'));
    }

    public function
library($class)
    {
       
set_include_path(get_include_path().PATH_SEPARATOR.'/lib/');
       
spl_autoload_extensions('.library.php');
       
spl_autoload($class);
    }

    public function
controller($class)
    {
       
$class = preg_replace('/_controller$/ui','',$class);
       
       
set_include_path(get_include_path().PATH_SEPARATOR.'/controller/');
       
spl_autoload_extensions('.controller.php');
       
spl_autoload($class);
    }

    public function
model($class)
    {
       
$class = preg_replace('/_model$/ui','',$class);
       
       
set_include_path(get_include_path().PATH_SEPARATOR.'/model/');
       
spl_autoload_extensions('.model.php');
       
spl_autoload($class);
    }

    public function
helper($class)
    {
       
$class = preg_replace('/_helper$/ui','',$class);

       
set_include_path(get_include_path().PATH_SEPARATOR.'/helper/');
       
spl_autoload_extensions('.helper.php');
       
spl_autoload($class);
    }

}

//call
autoloader::init();
?>
up
4
Rico
17 years ago
This autoload function searches for the class Location before requiring it. So there's no need of putting the classes all in one folder.

Requirements:
- the subfolders must be at least 3 letters long
- the filenames must be in the form CLASSNAME.class.php

Note:
- in this example the main class folder is 'lib'

define('ROOT_DIR', dirname(__FILE__).'/');

function __autoload($className) {
    $folder=classFolder($className);
    if($folder) require_once($folder.'/'.$className.'.class.php');
}

function classFolder($className,$folder='lib') {
    $dir=dir(ROOT_DIR.$folder);
    if($folder=='lib' && file_exists(ROOT_DIR.$folder.'/'.$className.'.class.php')) return $folder;
    else {
        while (false!==($entry=$dir->read())) {
            $checkFolder=$folder.'/'.$entry;
            if(strlen($entry)>2) {
                if(is_dir(ROOT_DIR.$checkFolder)) {
                    if(file_exists(ROOT_DIR.$checkFolder.'/'.$className.'.class.php')) return $checkFolder;
                    else {
                        $subFolder=classFolder($className,$checkFolder);
                        if($subFolder) return $subFolder;
                    }
                }
            }
        }
    }
    $dir->close();
    return 0;
}
up
5
zachera
15 years ago
I found out a neat way to centralize one single class which will give accessibility to other classes.  I also added a parameter to the __construct method which would be an array of classes you want loaded.  This isn't completely necessary, but it will stop "excessive memory" if you're loading a bunch of unused classes.

<?php
class Bot {
    private
$classes = array (
       
'Socket' => "connection/class.Socket.php",
       
'Input'  => "io/class.Input.php",
       
'Output' => "io/class.Output.php",
       
'Parse'  => "io/parse/class.Parse.php"
   
);
    public
$Socket, $Input, $Output, $Parse; // Accessible by other classes

   
public function __construct($load=false){
        if(
is_array($load)){
            foreach(
$load as $class){
                if(isset(
$this->classes[$class])){
                    require(
$this->classes[$class]);
                   
$this->$class = new $class($this);
                }
            }
        } else {
            foreach(
$this->classes as $class => $path){
                require(
$path);
               
$this->$class = new $class($this);
            }
        }
    }
}
?>
up
5
muratyaman at gmail dot com
16 years ago
__autoload() function can be very useful to optimize your code esp. when you have so many classes.

Unlike class extensions, optional parameters with class restrictions may not load your class.

<?php
class bClass{
  function
fun($p1, aClass $p2=NULL){
   
//do something
 
}
}

//depending on the usage
$b = new bClass();
$b->fun('No!');//this will not load class file for aClass
$b->fun('Really?', new aClass('Yes!'));//this will

?>

So, it's very encouraging to use classes everywhere!
Even encapsulating your functions inside simple classes to use like static modules, will help a lot!

Let's say, you have <b>50k</b> lines of code inside <b>100</b> classes/files.. If you need a simple task to do very quickly, you should not be loading all of those files, except the ones you need.

Though, it may be dangerous on some cases regarding the dependencies, load order, etc. Carefully design your classes.
up
7
qfox at ya dot ru
12 years ago
More simpler example of using spl_autoload_register in 5.3:
<?php
spl_autoload_register
(function($classname) /* usign $app */ {
 
# ... your logic to include classes here
});
?>
up
3
kalkamar at web dot de
15 years ago
Because static classes have no constructor I use this to initialize such classes.
The function init will (if available) be called when you first use the class.
The class must not be included before, otherwise the init-function wont be called as autoloading is not used.

<?php
function __autoload($class_name)
{
    require_once(
CLASSES_PATH.$class_name.'.cls.php');
    if(
method_exists($class_name,'init'))
       
call_user_func(array($class_name,'init'));
    return
true;
}
?>

I use it for example to establish the mysql-connection on demand.

It is also possilbe do add a destructor by adding this lines to the function:
<?php
if(method_exists($class_name,'destruct'))
   
register_shutdown_function(array($class_name,'destruct'));
?>
up
1
RQuadling at GMail dot com
18 years ago
An issue I've had with using the __autoload function is getting it into the application.

You have to have the function included in every topmost script. This is a pain if the entire application is OOP and an "app" can be just a component of another "app".

A solution I've found is to use php.ini's auto_prepend_file setting.

Mine is set to ...

auto_prepend_file = auto_loader.php

The auto_loader.php script contains a single function. The __autoload() function.

The include_dir path IS examined to find this file, so you can just put it with the rest of your includable files.

A useful additional facility here is that you could log which classes are used by a script at runtime. Very useful if you have object factories and can't know the load at design time.

Also, assigning the uncaught exception handler and the error handlers in this file means your entire site WILL have some global protection without you having to deal with it on a script by script basis.

If you do not have access to the PHP.INI file, or you are running on a shared server, you may not be able to set this property. In those cases, you may be able to set the value using .htaccess. (NOTE: UNTESTED as I don't use Apache).

<IfModule mod_php5.c>
  php_value auto_prepend_file "auto_loader.php"
</IfModule>

You COULD therefore have a different set of rules per subdomain (if you have multiple subdomains, say, live, test, beta, devel) or whatever takes your fancy.

For more details on this see the "Description of core php.ini directives" (http://www.php.net/manual/en/ini.core.php)
up
2
david dot thalmann at gmail dot com
17 years ago
Note to Ricos posting:
A lot of useless Coding. However, I improved the code, so now it will be able to find any folders ("." and ".." will not being tested... oO) and search as deep as possible. Now it will find CLASS_DIR/foo/bar.class.php also like CLASS_DIR/foo/bar/baz/buz/fii/and/so/on/class.php

Warning: This code will check ALL dirs who're "deeper" / "lower" than the class dir, so prevent deeply hidden files (or use just a few folders).

Improved Version:
<?php

// change this, if this code isn't "higher" than ALL classfiles
define("CLASS_DIR", dirname(__FILE__));

/**
* autoload classes (no need to include them one by one)
*
* @uses classFolder()
* @param $className string
*/
function __autoload($className) {
   
$folder = classFolder($className);

    if(
$folder)
        require_once(
$folder.$className.".class.php");
}

/**
* search for folders and subfolders with classes
*
* @param $className string
* @param $sub string[optional]
* @return string
*/
function classFolder($className, $sub = "/") {
   
$dir = dir(CLASS_DIR.$sub);
   
    if(
file_exists(CLASS_DIR.$sub.$className.".class.php"))
        return
CLASS_DIR.$sub;

    while(
false !== ($folder = $dir->read())) {
        if(
$folder != "." && $folder != "..") {
            if(
is_dir(CLASS_DIR.$sub.$folder)) {
               
$subFolder = classFolder($className, $sub.$folder."/");
               
                if(
$subFolder)
                    return
$subFolder;
            }
        }
    }
   
$dir->close();
    return
false;
}

?>
up
2
Peminator
14 years ago
My idea for autoloading FUNCTIONS however only in a weird way :

<?php
function ex($parms)
{
  
$argvar = func_get_args();
  
$func = $argvar[0];
  
$funcargs = array_slice($argvar,1);
  
if (
function_exists($func))
   {
  
$returnvalue = call_user_func_array($func,$funcargs);
   }
else
   {
  
$funcpath = "scripts/".$func.".php";
   require_once(
$funcpath);
  
   if (
function_exists($func))
      {
     
$returnvalue = call_user_func_array($func,$funcargs);
      } 
   else
      {
         die
"SORRY  $func IS NOT USABLE";
      }
   }

// return returned value :-)
return $returnvalue;
}
?>

USAGE EXAMPLE:
must be caled using the X function giving the real function as first parameter, like:
$result = ex("add",1,2);
// returns 3 if add function defined in add.php sums the first and second parameter..
up
1
gonix
17 years ago
in response to alexey at renatasystems dot org:

You may add ``global $somedata;`` before ``$somedata = 'Some data';`` and it should work as expected.

file bar.class.php:

<?php

global $somedata;
$somedata = 'Some data';    /* global scope in common way */

class bar {

   function
__construct()  
   {  
       global
$somedata;    /* reference to global scope variable */
     
      
if ( isset($somedata) )
       {
          
var_dump($somedata);
       }
       else
       {
           die(
'No data!');
       }
   }
}
?>

'common way':
<?php

require 'bar.class.php';

$foo = new bar();

?>

'__autoload way':
<?php

function __autoload($classname)
{
   require
$classname . '.class.php';
}

$foo = new bar();

?>

Both 'comon way' and '__autoload way' should give same result:
string(9) "Some data"
up
1
oliver dot strevel at gmail dot com
9 years ago
My autoloader function:

<?php

/**
* Funcion de autocarga de clases para php
* Se realiza la busqueda directamente sobre la raiz de la carpeta lib con el prefijo '.class.php'
*/
function __autoload( $class_name )
{
   
$invalidChars = array(
       
'.', '\\', '/', ':', '*', '?', '"', '<', '>', "'", '|'
   
);
   
   
$class_name = str_replace($invalidChars, '', $class_name);
   
   
$extension_prefix = '.class.php';
   
    if( !@include_once
$class_name . $extension_prefix )
    {
       
$path = 'lib'; // In this dir the function will search
       
       
foreach( new DirectoryIterator($path) as $file )
        {
            if(
$file->isDot()) { continue; }
           
            if(
$file->isDir())
            {
               
$file = $path . DIRECTORY_SEPARATOR . $file->getFilename() . DIRECTORY_SEPARATOR . $class_name . $extension_prefix;   
               
                if(
file_exists($file)) {
                    include_once
$file;
                }
            }
        }   
    }
    if (!
class_exists($class_name, false) || !interface_exists($class_name, false)) {
       
// return || Some tracking error task..
   
}
}
?>
up
2
me at mydomain dot com
18 years ago
You can enable this behaviour for undefined classes while unserializing objects by setting the .ini-variable 'unserialize_callback_func' to '__autoload'.
up
1
roman dot drapeko at gmail dot com
14 years ago
Hi there,

I have developed a small script, that can scan recursively folders and files ang generate array of associations between classes/interfaces and their locations. It accepts several incoming parameters and it's very simple to use.

An example of generated array is shown bellow.

<?php

    $autoload_list
= array (
     
'classes' => array (
       
'A' => array ('path' => 'Project/Classes/Children/A.php',
         
'extends' => array (), 'implements' => array ('I1')),
       
'C' => array ('path' => 'Project/Classes/C.php',
         
'extends' => array ('B'), 'implements' => array ('I1', 'I3')),
      ),
     
'interfaces' => array (
       
'I2' => array ('path' => 'Project/Interfaces/blablabla.php', 'extends' => array ('I1')),
       
'I1' => array ('path' => 'Project/Interfaces/I1.php', 'extends' => array ()),
      ),
    );
?>

When you know names and their locations, you know everything to load these classes.

It uses regular expressions to identify if class/interfaces is located in the current file.

I tried to post the code, but it's very long. You can download the script from http://wp.drapeko.com/store/php-autoloading-files/.
up
1
julian at jxmallett dot com
10 years ago
The tip to use spl_autoload_register() instead of __autoload() should be taken seriously. It seems that __autoload() doesn't always get called when calling an unloaded class within a class, eg:

<?php
class MyClass {
    public static function
doStuff() {
       
//do some stuff
       
$a = MyOtherClass::otherStuff();
    }
}
?>

Code similar to that gave me a 'class not found' error when using __autoload(). Using spl_autoload_register() with the exact same autoload function fixed the problem.
up
1
chris (at) xeneco (dot) co (dot) uk
15 years ago
I'm very taken with the autoload function, and thought I would share with you my implementation of it:
<?php
function __autoload($class_name) {

   
//my settings class is a singleton instance that has parsed an ini file containing the locations of all classes
   
$settings = Settings::Load();
   
$classes = $settings->getSettings('classes');

   
$path = $classes[$class_name];
   
    if(
file_exists($path)) {
        require_once(
$path);
        return
true;
    } else {
       
clearstatcache();
       
$classes = $settings->ReLoadSettings();
       
$path = $classes['classes'][$class_name];
    }
       
    if(
file_exists($path)) {
        require_once(
$path);
        return
true;
    } else {
        die(
"The requested library,".$class_name.", could not be found at ".$classes[$class_name][$i].". Please check your ini file");
    }
}
?>
up
1
La Hong Hai
2 years ago
I use namespaces that match the files' directory paths (root excluded) so all i have to do with spl_autoload_register is:
<?php
spl_autoload_register
(function (string $class): void {
    require
"{$_SERVER['DOCUMENT_ROOT']}\{$class}.php";
}
);
?>

No matter how complex your directory path is, there's no need for recursion or searching the whole project.
*You might want to use str_replace() to replace "\" to "/" if you're using Linux (untested)
up
0
instatiendaweb at gmail dot com
3 years ago
spl_autoload_register('autoloadficheros');
    function autoloadficheros ($nombre_clase) {
    global $nombre_clase2;
    static $x = 1;
//Como usar el espacio de nombre
    $nombre_clase4 = dirname($nombre_clase);
    if ($nombre_clase4 == 'eee'){
        $nombre_clase3 = basename($nombre_clase);
        $carpetanamespace = '\\eee\\';
        $nombre_clase2[0] = 'Extensiones soportadas' . spl_autoload_extensions('.php');
        $nombre_clase2[1] =  spl_autoload_functions();
        $nombre_clase2[] = "Medir ejecuciones " . $x++;
        $nombre_clase2[] = 'Nombre de clase añadida ==> ' . $nombre_clase3;
        $nombre_clase2[] = 'Directorio ==> ' . __DIR__ . $carpetanamespace .$nombre_clase3 . '.php';
        require __DIR__ . $carpetanamespace .  $nombre_clase3 . '.php';
        return;
    }
//Si no hay espacio de nombres la función normal
    $nombre_clase2[0] = 'Extensiones soportadas' . spl_autoload_extensions('.php');
    $nombre_clase2[1] =  spl_autoload_functions();
    $nombre_clase2[] = "Medir ejecuciones " . $x++;
    $nombre_clase2[] = 'Nombre de clase añadida ==> ' . $nombre_clase;
    $nombre_clase2[] = 'Directorio ==> ' . __DIR__ . '\\' .$nombre_clase . '.php';
    require __DIR__ . '\\' . $nombre_clase . '.php';
}/*Fin funcion autoload */
up
0
norwood at computer dot org
10 years ago
Autoloaders & Namespaces: The effective namespace of an autoloaded file must match that of its original reference; just  finding and loading the file isn't enough. (I know, seems obvious now, but...)

My namespaces may serve as hints to locations within the file system, and I tried to be cute:
     If a class (file) wasn't found where it was expected, my autoloader also looked in an alternate location. This worked fine, except that the alternate's own qualified namespace was thus slightly different (reflecting where *it* lived). So although the desired class was ultimately loaded (name and all), the original caller's reference remained unsatisfied because of the namespace discrepancy (as it should, really), but it was subtle.

Of course, this scheme works fine within the same namespace (explicit or not).

And kudos to the autoload devs for anticipating what could have been an endless autoload loop.
up
0
pier4r
10 years ago
Just a small autoload class (that works if you use corretly names, namespaces, uses and so on) found elsewhere with a small modification for linux:

<?php
//from http://www.phpfreaks.com / tutorial / oo - php - part - 1 - oop - in - full - effect
function __autoload($className)  {
 
var_dump($className);
 
$file = str_replace('\\', DIRECTORY_SEPARATOR, $className) . '.php';
 
var_dump($file);

 
var_dump(file_exists($file));
  if (!
file_exists($file)) {
    return
false;
  }
  else {
    require
$file;
    return
true;
  }
}
?>
up
0
tlang at halsoft dot com
11 years ago
This page states that autoloading does not work when PHP is used in CLI mode but a simple test seems to contradict this.

Create a file /tmp/Foo.php containing:

<?php
class Foo {
    public function
__construct() {
        echo
"Inside the Foo constructor\n";
    }
}
?>

Create a script (NOT in /tmp) containing:

<?php

function test_autoload($class) {
    require_once
'/tmp/'.$class.'.php';
}

spl_autoload_register('test_autoload');
$foo = new Foo();
?>

Execute the script on the command line. The echo statement in the constructor produces output to STDOUT.

This also works with __autoload

<?php

function __autoload($class) {
    require_once
'/tmp/'.$class.'.php';
}

$foo = new Foo();
?>
up
0
khan at swcombine dot com
14 years ago
As an addendum to #91119 I would suggest adding class_exists() into that solution. I've just implemented autoloading based on the code provided there and ran into a problem where a file had the same name as a class, existed in the directory structure prior to the file that had the actual class and as a result was being included first and resulting in a 'class not found' error.

<?php
if(file_exists($path)) {
    require_once
$path;
    if(
class_exists($class_name)) {
        return;
    }
}
?>
up
0
pinochet dot pl at gmail dot com
15 years ago
To use autoload function with namespaces you should remember to define it in main scope in "\" namespace.
up
0
richard [at ] xanox [dot] net
16 years ago
I've made this little script here which looks in a dir, and loads all the classed, and includes their files.

$myDirectory = opendir("required/classes");

// get each entry
while($entryName = readdir($myDirectory)) {
    $dirArray[] = $entryName;
}

// close directory
closedir($myDirectory);

//    count elements in array
$indexCount    = count($dirArray);
sort($dirArray);

for($index=0; $index < $indexCount; $index++) {
    if($dirArray[$index] != '.' AND $dirArray[$index] != '..') {
        include("required/classes/$dirArray[$index]");
        $classname = strtolower($dirArray[$index]);
        $classname = str_replace('.php','',$classname);
        $classinit = str_replace('.php','',$dirArray[$index]);

        $$classname = new $classinit;
    }
}
up
0
christian.reinecke at web.de
16 years ago
do not use is_subclass_of() in your __autoload() function to identify a class type and thereby its path (f.e exceptions). is_subclass_of() needs to know the class, but you want to check BEFORE you include the class.
up
0
alexey at renatasystems dot org
17 years ago
While using an "autoloading" method you should pay attention to variables scope. Because of new file will be included INSIDE of magic function __autoload - all of declared in such file global scope variables will be only available within this function and nowhere else. This will cause strange behaviour in some cases. For example:

file bar.class.php:

<?php

$somedata
= 'Some data';     /* global scope in common way */

class bar {

    function
__construct()   
    {   
        global
$somedata;    /* reference to global scope variable */
       
       
if ( isset($somedata) )
        {
           
var_dump($somedata);
        }
        else
        {
            die(
'No data!');
        }
    }
}
?>

Attempt to load this file in common way:

<?php

require 'bar.class.php';

$foo = new bar();

?>

this will output (as expected):

string(9) "Some data"

But in case of __autoload:

<?php

function __autoload($classname)
{
    require
$classname . '.class.php';
}

$foo = new bar();

?>

you could expect that this script will return the same but no, it will return "No data!", because defenition of $somedata after requiring treats as local within user-defined function __autoload().
up
0
dave60 /at/ gmail /dot/ com
18 years ago
In reply to quetzalcoatl:

Generally, I would advise for each class to have it's own file, and hold nothing besides that class. Just define __autoload() in a/the infrastructure file -- a/the file that does the behavioral logic, and there should be no need to redefine it in a class' file.
up
-1
tom at r dot je
14 years ago
To find out whether a class can be autoloaded, you can use autoload in this way:

<?php
//Define autoloader
function __autoload($className) {
    if (
file_exists($className . '.php')) require $className . '.php';
    else throw new
Exception('Class "' . $className . '" could not be autoloaded');
}

function
canClassBeAutloaded($className) {
    try {
       
class_exists($className);
        return
true;
    }
    catch (
Exception $e) {
        return
false;
    }
}
?>
up
-1
matias dot cohen at gmail dot com
15 years ago
Another way of throwing exceptions inside an __autoload() function:
<?php

function myExceptionHandler($e) {
   
// Add code here
}

set_exception_handler('myExceptionHandler');

function
__autoload($class) {
    if (
class_exists($class, false) || interface_exists($class, false)) {
        return;   
    }
    try {
        @require_once(
'path/to/' . $class . '.php');
        if (!
class_exists($class, false) || !interface_exists($class, false)) {
            throw new
Exception('Class ' . $class . ' not found');
        }
    }
    catch (
Exception $e) {

       
myExceptionHandler($e);
    }
}

?>
up
-1
claude dot pache at gmail dot com
15 years ago
About static classes that need initialisation before use (problem discussed by adam at greatbigmassive dot net and kalkamar at web dot de below).

Simple problems have often simple solutions. Here is my approach:

First, my __autoload function is very simple:
<?php
function __autoload ($class_name)
{
    if (
preg_match('|^\w+$|', $class_name))
        include
"./packages/$class_name.php";
}
?>
(The "if/preg_match" line is just a simple yet robust security check. Moreover I use "include" and not "require"/"require_once", so that if the file is not found, the __autoload function does nothing, and my script dies eventually with a meaningful "Class 'foo' not found"  fatal error.)

Now, when I define a class "foo" which requires initialisation before use, I just write the initialisation code after the definition of the class in the file "packages/foo.php":

<?php
/** Content of file "packages/foo.php" **/
class foo
{
   
/* definition of the class is found here */
}

/* initialisation code of the class is found here. */

/** End of file "packages/foo.php" **/
?>

That's it. No need for an <? init() ?> or a <? __construct() ?> method.
To Top