dc2.jd.com auto.php,自动加载类 - [ php中文手册 ] - 在线原生手册 - php中文网

用户评论:

[#1]

dsimer at gmail dot com [2015-04-02 01:10:19]

On the if/else, you are better off either entering a break after success and continue on else (if you feel as though you have to return something), or otherwise not putting in an else.  the else with return will cause a premature end to the function.

Also, if you use an array of directories, it may be a good idea to enter a blank ('') as the first value so that the script will check locally.

[#2]

oliver dot strevel at gmail dot com [2014-07-14 00:50:41]

My autoloader function:

{$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 searchforeach( newDirectoryIterator($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..}

}?>

[#3]

norwood at computer dot org [2014-01-11 16:12:40]

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.

[#4]

pier4r [2013-12-31 14:46:51]

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:

if (!file_exists($file)) {

returnfalse;

}

else {

require$file;

returntrue;

}

}?>

[#5]

julian at jxmallett dot com [2013-12-15 23:41:07]

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:

public static functiondoStuff() {//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.

[#6]

tlang at halsoft dot com [2013-02-14 21:56:48]

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:

public function__construct() {

echo"Inside the Foo constructor\n";

}

}?>

Create a script (NOT in /tmp) containing:

require_once'/tmp/'.$class.'.php';

}spl_autoload_register('test_autoload');$foo= newFoo();?>

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

This also works with __autoload

require_once'/tmp/'.$class.'.php';

}$foo= newFoo();?>

[#7]

qfox at ya dot ru [2011-11-16 14:48:18]

More simpler example of using spl_autoload_register in 5.3:

spl_autoload_register(function($classname){# ... your logic to include classes here});?>

[#8]

fka at fatihkadirakin dot com [2010-07-31 18:16:34]

Or you can use this, without using any "require/include":

public static$loader;

public static functioninit()

{

if (self::$loader==NULL)self::$loader= newself();

returnself::$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 functionlibrary($class)

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

}

public functioncontroller($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 functionmodel($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 functionhelper($class)

{$class=preg_replace('/_helper$/ui','',$class);set_include_path(get_include_path().PATH_SEPARATOR.'/helper/');spl_autoload_extensions('.helper.php');spl_autoload($class);

}

}//callautoloader::init();?>

[#9]

ej at campbell dot name [2010-04-03 11:21:41]

You don't need exceptions to figure out if a class can be autoloaded. This is much simpler.

if (file_exists($className.'.php')) {

require_once$className.'.php';

returntrue;

}

returnfalse;

}

functioncanClassBeAutloaded($className) {

returnclass_exists($className);

}?>

[#10]

tom at r dot je [2010-03-11 03:30:28]

To find out whether a class can be autoloaded, you can use autoload in this way:

if (file_exists($className.'.php')) require$className.'.php';

else throw newException('Class "'.$className.'" could not be autoloaded');

}

functioncanClassBeAutloaded($className) {

try {class_exists($className);

returntrue;

}

catch (Exception $e) {

returnfalse;

}

}?>

[#11]

Anonymous [2010-02-08 15:35:17]

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

[#12]

khan at swcombine dot com [2009-11-05 05:38:52]

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.

require_once$path;

if(class_exists($class_name)) {

return;

}

}?>

[#13]

h762017(at)stud(dot)u-szeged(dot)hu [2009-08-20 19:24:11]

Hi,

Because the scripting engine just find the class declaration in the body of the __autoload() function, you also can declare the missing class in the __autoload() function. (No need to include or require a file.)

Let's see the following code:

Example 1.:

echo"Now loading:$className
";

classSuperClass{

}

}

classDerivedClassextendsSuperClass{

}

classAnotherDerivedClassextendsSuperClass{

}?>

The scripting engine will found the SuperClass class.

Example 2.:

You also can do it with the eval function, and if you dinamycally declare the class, you don't get a Fatal Error, and you can do many interesting things with the eval function;)

echo"Now loading:$className
";

eval("class$className{}");

}

classDerivedClassextendsSuperClass{

}

classAnotherDerivedClassextendsSuperClass{

}?>

[#14]

Peminator [2009-07-07 07:01:06]

My idea for autoloading FUNCTIONS however only in a weird way :

{$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$funcIS 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..

[#15]

roman dot drapeko at gmail dot com [2009-04-05 04:33:33]

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.

$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/.

[#16]

claude dot pache at gmail dot com [2009-03-11 19:04:55]

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:

{

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":

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

[#17]

jarret dot minkler at gmail dot com [2009-03-07 22:55:20]

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.

[#18]

pinochet dot pl at gmail dot com [2009-01-04 13:11:04]

To use autoload function with namespaces you should remember to define it in main scope in "\" namespace.

[#19]

zachera [2008-12-31 16:55:30]

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.

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 classespublic function__construct($load=false){

if(is_array($load)){

foreach($loadas$class){

if(isset($this->classes[$class])){

require($this->classes[$class]);$this->$class= new$class($this);

}

}

} else {

foreach($this->classesas$class=>$path){

require($path);$this->$class= new$class($this);

}

}

}

}?>

[#20]

kalkamar at web dot de [2008-10-07 10:23:41]

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.

{

require_once(CLASSES_PATH.$class_name.'.cls.php');

if(method_exists($class_name,'init'))call_user_func(array($class_name,'init'));

returntrue;

}?>

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:

[#21]

jbarker at erepublic dot com [2008-09-17 08:34:05]

In a subclass, I was trying to call an overridden parent method with an arbitrary number of arguments:

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

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

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:

{

if ('parent'!=$cls)

{

require("class.$cls.php");

}

}?>

Tested on Linux with PHP 5.1.6 and 5.2.5.

[#22]

andrzeje from wit.edu.pl [2008-09-13 20:18:00]

Throwing versions of __autoload based on eval will fail if __autoload will be caled with interface name.

[#23]

matias dot cohen at gmail dot com [2008-08-01 16:33:53]

Another way of throwing exceptions inside an __autoload() function:

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 newException('Class '.$class.' not found');

}

}

catch (Exception $e) {myExceptionHandler($e);

}

}?>

[#24]

chris (at) xeneco (dot) co (dot) uk [2008-07-04 06:21:35]

I'm very taken with the autoload function, and thought I would share with you my implementation of it:

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

returntrue;

} else {clearstatcache();$classes=$settings->ReLoadSettings();$path=$classes['classes'][$class_name];

}

if(file_exists($path)) {

require_once($path);

returntrue;

} else {

die("The requested library,".$class_name.", could not be found at ".$classes[$class_name][$i].". Please check your ini file");

}

}?>

[#25]

Chris Continanza [2008-04-29 11:43:08]

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;

}

}

}

[#26]

james dot dot dot dunmore at gmail dot com [2008-04-18 04:43:16]

Andrew: 03-Nov-2006 12:26

That seems a bit messy to me, this is a bit neater:

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;

}

}

}

[#27]

muratyaman at gmail dot com [2008-01-28 07:57:10]

__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.

functionfun($p1,aClass $p2=NULL){//do something}

}//depending on the usage$b= newbClass();$b->fun('No!');//this will not load class file for aClass$b->fun('Really?', newaClass('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 50k lines of code inside 100 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.

[#28]

ostapk [2007-12-19 14:46:48]

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

[#29]

richard [at ] xanox [dot] net [2007-12-05 07:46:38]

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 

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;

}

}

[#30]

rojoca [2007-10-04 20:38:44]

Be careful when using eval (as always) in __autoload. The following:

<?phpecho '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.

[#31]

christian.reinecke at web.de [2007-09-23 09:28:12]

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.

[#32]

rlee0001 at sbcglobal dot net [2007-08-30 13:16:22]

If you would like __autoload to throw an exception when the class cannot be loaded instead of causing a fatal error, consider this:

{$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('

Not Found

The requested page %s was not found on this server.


$id$',$_SERVER['REQUEST_URI']);

}?>

[#33]

emcmanus at gmail dot com [2007-07-16 18:04:45]

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.

[#34]

peter dot gooman at gmail dot com [2007-06-17 20:33:02]

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.

[#35]

Andrea Giammarchi [2007-03-21 03:54:33]

Another workaround for Exception problem (Klaus Schneider style)

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 {

newUndefined;

}

catch(Undefined $e) {

echo$e->getMessage();

}// You should use generic Exception toocatch(Exception $e) {

echo$e->getMessage();

}?>

[#36]

Klaus Schneider [2007-03-01 07:35:22]

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

{// Do your stuff to load a class here, set $ok if everything went fine.if (!$ok) {

eval("class$className{};");

throw newException('My message');

}// if}

try {UndefinedClass::undefinedFunction();

} catch (Exception $ex) {

echo$ex->getMessage();

}// try/catch?>

Output: "My Message".

:-)

[#37]

david dot thalmann at gmail dot com [2007-02-02 07:19:42]

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:

if($folder)

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

}functionclassFolder($className,$sub="/") {$dir=dir(CLASS_DIR.$sub);

if(file_exists(CLASS_DIR.$sub.$className.".class.php"))

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

returnfalse;

}?>

[#38]

Rico [2007-01-04 05:00:20]

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;

}

[#39]

sandrejev at gmail dot com [2006-11-08 23:23:40]

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.

classAutoloadExceptionRetranslatorextendsException{

public function__construct($serializedException)

{

throwunserialize($serializedException);

}

}

function__autoload($classname)

{

if(!file_exists($classname))

{$autoloadException=serialize(newAutoloadException("Class$classnamecould 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= newAnyNonExistantClass();

}

catch (AutoloadException $e)

{print_r($e->getTrace());

}?>

[#40]

andrew dot delete dot cornes at gmail dot delete dot com [2006-11-03 04:26:50]

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

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.

[#41]

Chris Corbyn (chris AT w3style.co.uk) [2006-09-08 06:23:45]

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:

}classServiceLocator{protected static$locators= array();public static functionattachLocator(Locator $locator,$key)

{self::$locators[$key] =$locator;

}public static functiondropLocator($key)

{

if (self::isActiveLocator($key))

{

unset(self::$locators[$key]);

returntrue;

}

else returnfalse;

}public static functionisActiveLocator($key)

{

returnarray_key_exists($key,self::$locators);

}public functionload($class)

{

foreach (self::$locatorsas$key=>$obj)

{

if ($obj->canLocate($class))

{

require_once$obj->getPath($class);

if (class_exists($class)) return;

}

}

}

}function__autoload($class)

{$locator= newServiceLocator();$locator->load($class);

}?>

An example Use Case:

protected$base='.';

public function__construct($directory='.')

{$this->base= (string)$directory;

}

public functioncanLocate($class)

{$path=$this->getPath($class);

if (file_exists($path)) returntrue;

else returnfalse;

}

public functiongetPath($class)

{

return$this->base.'/'.str_replace('_','/',$class) .'.php';

}

}// ... attach it ...ServiceLocator::attachLocator(newPearLocator(),'PEAR');// ... and code away....$foo= newFoo_Test();?>

[#42]

gonix [2006-08-03 06:39:52]

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:

function__construct()

{

global$somedata;if ( isset($somedata) )

{var_dump($somedata);

}

else

{

die('No data!');

}

}

}?>

'common way':

'__autoload way':

{

require$classname.'.class.php';

}$foo= newbar();?>

Both 'comon way' and '__autoload way' should give same result:

string(9) "Some data"

[#43]

alexey at renatasystems dot org [2006-07-06 12:15:21]

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:

$somedata='Some data';classbar{

function__construct()

{

global$somedata;if ( isset($somedata) )

{var_dump($somedata);

}

else

{

die('No data!');

}

}

}?>

Attempt to load this file in common way:

this will output (as expected):

string(9) "Some data"

But in case of __autoload:

{

require$classname.'.class.php';

}$foo= newbar();?>

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

[#44]

RQuadling at GMail dot com [2006-03-08 00:55:45]

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

php_value auto_prepend_file "auto_loader.php"

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)

[#45]

dave60 /at/ gmail /dot/ com [2005-12-29 13:25:53]

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.

[#46]

me at mydomain dot com [2005-11-11 16:07:54]

You can enable this behaviour for undefined classes while unserializing objects by setting the .ini-variable 'unserialize_callback_func' to '__autoload'.

[#47]

php at kaiundina dot de [2005-09-20 11:42:11]

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:

{// just say helloecho'

static constructor
';

}// default dynamic constructor operationpublic function__construct()

{// just say helloecho'

dynamic constructor
';

}

}?>

Content of index.php5:

{// load the classrequire_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 constructorcall_user_func($staticConstructorReference);

}

}// create an example object to see both constructors being executed$article= newMyObject();?>

[#48]

scott at webscott dot com [2005-05-04 05:40:51]

__autoload() seems to work when saving objects as session variables as well:

classLoader.php

require_once("$className.php");

}?>

testClass.php

function__construct($propValue) {$this->prop1=$propValue;

}

functionshowProp() {

return$this->prop1;

}

}?>

page1.php

echo'Go to page 2';?>

page2.php

echo$_SESSION['testObj']->showProp();// displays foo?>

Works with multiple session objects as well.  Tested on a Win2k/IIS machine.

[#49]

trini0 [2005-02-01 20:04:17]

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...

[#50]

petyo()architect . bg [2005-01-30 01:27: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.

[#51]

thomas dot revell at uwe dot ac dot uk [2005-01-27 06:31:22]

If you want to throw an exception if a class isn't defined yet, use class_exists ():

throw newException("Class$classNameis not defined.");

}?>

The second parameter indicates whether or not the __autoload () function should be called before checking for the class's existence.

[#52]

nhartkamp at eljakim dot N0SP4M dot nl [2004-12-11 09:14:51]

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值