PHP
downloads | documentation | faq | getting help | mailing lists | wiki | reporting bugs | php.net sites | links | conferences | my php.net

search for in the

Constructors and Destructors> <The Basics
Last updated: Fri, 28 Nov 2008

view this page in

Autoloading Objects

Many developers writing object-oriented applications create one PHP source file per-class definition. One of the biggest annoyances is having to write a long list of needed includes at the beginning of each script (one for each class).

In PHP 5, this is no longer necessary. You may define an __autoload function which is automatically called in case you are trying to use a class/interface which hasn't been defined yet. By calling this function the scripting engine is given a last chance to load the class before PHP fails with an error.

Note: Exceptions thrown in __autoload function cannot be caught in the catch block and results in a fatal error.

Note: Autoloading is not available if using PHP in CLI interactive mode.

Note: If the class name is used e.g. in call_user_func() then it can contain some dangerous characters such as ../. It is recommended to not use the user-input in such functions or at least verify the input in __autoload().

Example #1 Autoload example

This example attempts to load the classes MyClass1 and MyClass2 from the files MyClass1.php and MyClass2.php respectively.

<?php
function __autoload($class_name) {
    require_once 
$class_name '.php';
}

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

Example #2 Autoload other example

This example attempts to load the interface ITest.

<?php

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

class 
Foo implements ITest {
}

/*
string(5) "ITest"

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



Constructors and Destructors> <The Basics
Last updated: Fri, 28 Nov 2008
 
add a note add a note User Contributed Notes
Autoloading Objects
lskatz at gmail dot com
21-Oct-2008 12:45
Building on Chris Continanza's function, I wanted to add in multiple filename options since sometimes I add ".class.php" and other times ".php".

<?php
 
function __autoload($class_name) {
   
$include_path = get_include_path();
   
$include_path_tokens = explode(':', $include_path);

    foreach(
$include_path_tokens as $prefix){
     
$path[0] = $prefix . '/' . $class_name . '.php';
     
$path[1]= $prefix . '/' . $class_name . '.class.php';
      foreach(
$path as $thisPath){
        if(
file_exists($thisPath)){
          require_once
$thisPath;
          return;
        }
      }
    }
  }
?>
xavierlesa
09-Oct-2008 08:39
A simple way to autoload all classes

<?php
function autoload($path=false)
    {
        if(!
$path) $path=PATH_MOD;
       
exec('ls '.$path.'mod_*', $f);
        foreach(
$f as $mod)
        {
           
$module=str_replace('.php','',str_replace($path.'mod_','',$mod));
            if(!
is_object($this->$module))
               {
                   if(require_once(
$mod))
                {   
                   
$this->modulos[$module]=new $module;
                   
$this->module=$this->modulos[$module];
                }
                else
                {
                   
$this->error='error el modulo '.$mod.' no exite, o no tiene permisos';
                    return
false;
                }
            }
        }
        return
true;
    }
?>
kalkamar at web dot de
07-Oct-2008 10:23
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'));
?>
jbarker at erepublic dot com
17-Sep-2008 08:34
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.
andrzeje from wit.edu.pl
13-Sep-2008 08:18
Throwing versions of __autoload based on eval will fail if __autoload will be caled with interface name.
<?php
/* eval+throw __autoload
 */
class Cls implements Iface {/* ... */}; // Error
?>
sebasg37 at gmail dot com
23-Aug-2008 04:09
When __autoload doesn't seem to work or if you are in PHP 4:

<?php
$include_paths
= explode( PATH_SEPARATOR , get_include_path() );
    foreach(
$include_paths as $path ) {
        if(
is_dir( $path ) ) {
           
$d = opendir( $path );
            while (
false !== ($f = readdir($d))) {
               if(
ereg( "^.*\.php$" , $f ) && strstr( $path , ABS_PATH ) ) { ## avoid PEAR and other files for automatic requirement
                   
require_once $f;
               }
            }
           
closedir($d);
        }
    }

// replace ABS_PATH with your app root
?>
matias dot cohen at gmail dot com
01-Aug-2008 04:33
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);
    }
}

?>
chris (at) xeneco (dot) co (dot) uk
04-Jul-2008 06:21
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");
    }
}
?>
Chris Continanza
29-Apr-2008 11:43
Decided to warm up to autoload,
but wanted it to use the include_path.
Good default behavior.

function __autoload($class_name) {
      $include_path = get_include_path();
      $include_path_tokens = explode(':', $include_path);
     
      foreach($include_path_tokens as $prefix){
         $path = $prefix . '/' . $class_name . '.php';
         if(file_exists($path)){
            require_once $path;
            return;
          }
       } 
  }
james dot dot dot dunmore at gmail dot com
18-Apr-2008 04:43
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;
            }           
        }
    }
richard at richard-sumilang dot com
27-Mar-2008 02:11
[ >= php5.3]

If you are using namespaces and this is MyClass.php:

<?php
namespace com
::richardsumilang::utils;

class
MyClass{
  
// ... code ...
}

?>

And say we are using MyClass in another file like so...

<?php

use com::richardsumilang::utils as Utils;

$foo=new Utils::MyClass();

?>

And lastly if this was our __autoload method:

<?php

function __autoload($class){
   echo
"Trying to load: ", $class,"\n";
}

?>

That will echo "com::richardsumilang::util::MyClass" and not "Utils::MyClass". It is very useful that it is passing the full name of the class and not the alias name you use so if your classes followed your directory structure then you would be ok:

com::richardsumilang::utils::MyClass = com/richardsumilang/utils/MyClass.php

- Richard Sumilang
jjfitzgerald at gmail dot com
30-Jan-2008 07:39
Regardless of the situation you're in (developing a web-app or writing some code that may use someone else's web-app), always a good idea not to use __autoload() but instead write a differently-named function and register it as an autoloader:

<?php

function class_autoloader($c) {
    if(
file_exists(dirname(__FILE__). "/classes/{$c}.php") && include_once(dirname(__FILE__). "/classes/{$c}.php")) {
        return
true;
    } else {
       
trigger_error("Could not load class '{$c}' from file '{$c}.php'", E_USER_WARNING);
        return
false;
    }
}

spl_autoload_register("class_autoloader");

?>

Using spl_autoload_register(), the function class_autoloader() will now be used when classes are instantiated, just like __autoload() does, but without the potential conflict with other web-apps __autoload() function.
muratyaman at gmail dot com
28-Jan-2008 07:57
__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.
Mexi-Fry
16-Jan-2008 05:19
Seems like a strange layer of obscurity to me (to be honest).  It would be really handy if that could be implemented and remain in memory though, enabling pages to instantiate classes without having to repeatedly include documents.  Being able to construct an object without having to include the document that contained it (AND without having to include that function in some form on each document) would be very nice.
boltclock aInACircle NOVALISTIC dot com
11-Jan-2008 09:31
You can allow __autoload() to throw exceptions without resulting in fatal errors by trying class_exists(), literally.

<?php

function __autoload($class)
{
    if (
file_exists($file = "./inc/$class.php"))
    {
        include(
$file);
    }
    else
    {
        throw new
Exception("Class $class not found");
    }
}

// By 'literally', I mean this
try
{
   
// Since the second argument defaults to true, __autoload()
    // will be called from this function
   
class_exists('MyClass');
}
catch (
Exception $e)
{
   
// Catch the exception and handle it as usual
   
die($e->getMessage());
}

// Safely initialize an object from the class
$class = new MyClass();

?>
ostapk
19-Dec-2007 02:46
To sandrejev at gmail dot com below:

if you create the exception in the __autoload() and serialize it, then when you try to access the same missing class later (in another place in the code), then the exception will contain invalid stack trace.

Also, here's an excellent blog post that discusses the consequences of using eval() as well as provides an example to handle static method calls and namespaces: http://www.onphp5.com/article/61
richard [at ] xanox [dot] net
05-Dec-2007 07:46
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;
    }
}
rojoca
04-Oct-2007 08:38
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.
christian.reinecke at web.de
23-Sep-2007 09:28
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.
knoopx at gmail dot com
06-Sep-2007 12:56
Quick and easiest way to be able to throw exceptions on __autoload() method:

<?php
function __autoload($class_name) {
    
find_file($class_name); //your own routine to locate the class file
    
if (!class_exists($class_name, false)) {
         eval(
"class $class_name {}");
         throw new
Exception('Class not found');
     }
}
?>
rlee0001 at sbcglobal dot net
30-Aug-2007 01:16
If you would like __autoload to throw an exception when the class cannot be loaded instead of causing a fatal error, consider this:

<?php
function __autoload ($className)
{
   
$fileName = str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
   
$status = (@include_once $fileName);
       
    if (
$status === false) {
        eval(
sprintf('class %s {func' . 'tion __construct(){throw new Project_Exception_AutoLoad("%s");}}', $className, $className));
    }  
}

$pageController = 'Project_My_Class'; // "Project/My/Class.php"

try {
 
$obj = new $pageController();
} catch (
Project_Exception_AutoLoad $e) {
   
header('HTTP/1.0 404 Not Found');
   
printf('<h1>Not Found</h1><p>The requested page %s was not found on this server.</p><hr /><em>$id$</em>', $_SERVER['REQUEST_URI']);
}
?>
emcmanus at gmail dot com
16-Jul-2007 06:04
Note: if you're experiencing unexpected "failed opening required 'filename.php' (include..." errors:

If you placed your autoload function in an external file which you're requiring at the head of every script, be cautious of some odd behavior regarding PHP's idea of the current working directory.

I ran into some unexpected path issues when my include file was placed in a subdirectory directory. The solution to my problems was to make sure that the autoload script being included is in the same directory as the calling script.
peter dot gooman at gmail dot com
17-Jun-2007 08:33
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.
Andrea Giammarchi
21-Mar-2007 04:54
Another workaround for Exception problem (Klaus Schneider style)

<?php
define
('CLASS_DIR', 'php/classes/');
function
__autoload($name) {
    if(
$exists = !class_exists($name) && file_exists($class = CLASS_DIR.$name.'.class.php'))
        require
$class;
    elseif(!
$exists) {
        eval(
'class '.$name.' extends Exception {}');
        throw new
$name('[__autoload] this file doesn\'t exists: '.$class);
    }
}

try {
    new
Undefined;
}
catch(
Undefined $e) {
    echo
$e->getMessage();
}
// You should use generic Exception too
catch(Exception $e) {
    echo
$e->getMessage();
}
?>
Klaus Schneider
01-Mar-2007 07:35
I just stumbled over one quite nice solution to the __autoload-exception problem.  It allows for any kind of exception to be thrown inside __autoload().

It appears one has to define the requested class (using "eval", which is not nice but inevitable here) and after that can simply throw an exception (and catch it if so desired):

<?php
function __autoload($className)
{
  
// Do your stuff to load a class here, set $ok if everything went fine.
  
if (! $ok) {
      eval(
"class $className{};");
      throw new
Exception('My message');
   }
// if
}

try {
  
UndefinedClass::undefinedFunction();
} catch (
Exception $ex) {
   echo
$ex->getMessage();
}
// try/catch
?>

Output: "My Message". 

:-)
david dot thalmann at gmail dot com
02-Feb-2007 07:19
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;
}

?>
Rico
04-Jan-2007 05:00
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;
}
sandrejev at gmail dot com
08-Nov-2006 11:23
Here is the most complete version of __autoload exception i guess.
The best thing is that it can throw any exception plus the exception is fully functional.

<?php
class AutoloadException extends Exception { }

class
AutoloadExceptionRetranslator extends Exception
{
    public function
__construct($serializedException)
    {
        throw
unserialize($serializedException);
    }
}

function
__autoload($classname)
{
    if(!
file_exists($classname))
    {
       
$autoloadException = serialize(new AutoloadException("Class $classname could not be found"));

        return eval(
"
            class $classname
            {
                function __construct(\$a=0, \$b=0, \$c=0, \$d=0, \$e=0, \$f=0, \$g=0, \$h=0, \$i=0)
                {
                    throw new AutoloadExceptionRetranslator('$autoloadException');
                }
            }
        "
);
    }
    else
    {
        require_once
$classname;
    }
}

try
{
   
$anyObject = new AnyNonExistantClass();
}
catch (
AutoloadException $e)
{
   
print_r($e->getTrace());
}
?>
andrew dot delete dot cornes at gmail dot delete dot com
03-Nov-2006 04:26
If you'd like '__autoload()' to support multiple class folders, each containing multiple class files (one per class), you may want to try something like this (file '__autoload.php'):

<?php

define
('CLASS_FILENAME_SUFFIX', '.class.php');

function
__autoload($className)
{
   
$__autoloadAbsolutePath = dirname(__FILE__);

   
// 'pathStart' is your web application root folder.
    // (This may or may not be where '__autoload.php'
    // resides; let's assume here that it resides one
    // level 'below' the web app root.)
   
$pathStart = $__autoloadAbsolutePath .
       
DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR;

   
// 'classPath' is a list of class folders to look in.
    // (In this example, there's just one: 'classlibs/lib1'.
    // To add more, simply append them; start with
    // 'PATH_SEPARATOR . $pathStart .', and off you go...)
   
$classPath = PATH_SEPARATOR . $pathStart .
       
'classlibs' . DIRECTORY_SEPARATOR . 'lib1';

   
// Add list of class folders to 'include_path' for the
    // forthcoming 'require()' (or similar directive).
   
$oldIncludePath = get_include_path();
   
set_include_path($oldIncludePath . $classPath);

    require_once(
$className . CLASS_FILENAME_SUFFIX);

   
// Reinstate initial 'include_path'.
   
set_include_path($oldIncludePath);
}

?>

As your web application develops, new paths containing class files can be added into the '$classPath' variable within '__autoload()'. If hard-coding the '$classPath' variable isn't to your taste, you could arrange for its value to come from 'outside' in whatever way you like.

Any comments gratefully received.
Chris Corbyn (chris AT w3style.co.uk)
08-Sep-2006 06:23
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();

?>
gonix
03-Aug-2006 06:39
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"
alexey at renatasystems dot org
06-Jul-2006 12:15
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().
RQuadling at GMail dot com
08-Mar-2006 12:55
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)
dave60 /at/ gmail /dot/ com
29-Dec-2005 01:25
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.
me at mydomain dot com
11-Nov-2005 04:07
You can enable this behaviour for undefined classes while unserializing objects by setting the .ini-variable 'unserialize_callback_func' to '__autoload'.
quetzalcoatl(AT)poczta.fm
05-Nov-2005 03:21
While __autoloading is a nice feature, one can stumble upon small problem with it. Imagine:

file A.php:
<?
  
function __autoload($cname)
   {  require_once
"include/$cname.php";}
   }

  
B::testC();
?>

file B.php:
<?
  
function __autoload($cname)
   {  require_once
"include/$cname.php";}
   }

   class
B
  
{  public static function test()
       { 
C::testMe();
       }
   }
?>

file C.php:
<?
  
class C
  
{  public static function testMe()
       {  print(
"OK!");
       }
   }
?>

Now, running file A.php will result in an error.. because from A's point of view, function __autoload is declared twice - once in A.php, and in required_once'd B.php, too! [Not mentioning that C.php and many many many other required or included files could use it too :) ] So, of course we can remove the duplicate __autoload functions from B.php and any other required files. Thus, we either disallow usage of B.php independently (and other required-able/include-able files!) , as without the __autoload it can not work -- or we have to manually require_once its dependecies, thus making manually the job of __autoload. Irritating, isn't it?

A simple trick can help us here. Every file you would place an __autoload function, place instead something like:
    if(!function_exists("__autoload"))
    {   //your __autoload declaration, for example:
        function __autoload($cname)
        {  require_once "include/$cname.php";
        }
    }

When I first tried it, I was really surprised that you can control functions' declaration with simple IF, without any evals or other tricks.

Well.. it's probably a basic "trick", but I didn't notice it anywhere. Feel free to remove it if it was already posted somewhere:)
php at kaiundina dot de
20-Sep-2005 11:42
The autoload-feature allows to add the behavior of static constructors (like in C#). Static constructors should be called on the first occurence of a class reference - typically a 'new' operator or a static call to a class's operation.

They can be used used to initialize complex static properties.

And here is an easy and save way how it can be done:

Content of MyClass.class.php5:
<?php

// demo class persisting of a static and a dynamic constructor
class MyClass
{
   
   
// static constructor operation
   
public static function _construct()
    {
       
// just say hello
       
echo '<div>static constructor</div>';
    }
   
   
// default dynamic constructor operation
   
public function __construct()
    {
       
// just say hello
       
echo '<div>dynamic constructor</div>';
    }
   
}

?>

Content of index.php5:
<?php

// declare handler for any unknown class request
function __autoload($aClassName)
{
   
// load the class
   
require_once ($aClassName . '.class.php5');

   
// create a reference to the static constructor's operation
   
$staticConstructorReference = array($aClassName, '_construct');
   
   
// if the static constructor was declared properly...
   
if (is_callable($staticConstructorReference))
    {
       
// call the static constructor
       
call_user_func($staticConstructorReference);
    }
}

// create an example object to see both constructors being executed
$article = new MyObject();

?>
scott at webscott dot com
04-May-2005 05:40
__autoload() seems to work when saving objects as session variables as well:

classLoader.php
<?php
function __autoload($className) {
  require_once(
"$className.php");
}
?>

testClass.php
<?php
class testClass {
  function
__construct($propValue) {
   
$this->prop1 = $propValue;
  }

  function
showProp() {
    return
$this->prop1;
  }
}
?>

page1.php
<?php
require_once('classLoader.php');
session_start();
$_SESSION['testObj'] = new testClass('foo');
echo
'<a href="page2.php">Go to page 2</a>';
?>

page2.php
<?php
require_once('classLoader.php');
session_start();
echo
$_SESSION['testObj']->showProp(); // displays foo
?>

Works with multiple session objects as well.  Tested on a Win2k/IIS machine.
trini0
01-Feb-2005 08:04
Be careful with using that eval() trick within __autoload().
If you use reflection in your code, the so called trick,
*can* provide ill side effects.
For example ->
$reflection = new reflectionClass('some_class');
if (FALSE === $reflection->isSubClassOf('another_class'))
{
    throw new Exception('Class "some_class" must extend base class "another_class"');
}

If the real class "another_class" doesnt exist at the time, or "some_class" doesn't extend "another_class", with the reflection test, the so called eval() trick, creates a dummy "another_class",
thereby making the reflection test useless...
petyo()architect . bg
30-Jan-2005 01:27
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.
thomas dot revell at uwe dot ac dot uk
27-Jan-2005 06:31
If you want to throw an exception if a class isn't defined yet, use class_exists ():

<?php
// See if the class is defined
if (!class_exists ($className, false)) {
    throw new
Exception ("Class $className is not defined.");
}
?>

The second parameter indicates whether or not the __autoload () function should be called before checking for the class's existence.
nhartkamp at eljakim dot N0SP4M dot nl
11-Dec-2004 09:14
The following might provide a good work-around for throwing exceptions from the __autoload function when a file containing the correct class doesn't exists.

function __autoload ($class_name) {
  $file = 'system/objects/' . $class_name . '.inc.php';
  if (!file_exists ($file)) {
    return eval ("class $class_name {" .
                 "  function $class_name () {" .
                 "    throw new Exception ();" .
                 "  }" .
                 "}");
  }
  require_once ($file);
}

Cheers,
Nolan

Constructors and Destructors> <The Basics
Last updated: Fri, 28 Nov 2008
 
 
show source | credits | stats | sitemap | contact | advertising | mirror sites