|
 |
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 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.
Замечание:
Exceptions thrown in __autoload function cannot be caught in the
catch block and results in
a fatal error.
Пример 19-6. 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();
?>
|
|
Autoloading Objects
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'; class bar {
function __construct()
{
global $somedata; 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().
phpman at generic dot depoll dot de
16-May-2006 02:47
"Inspired" by unspammable-iain at iaindooley dot com, here is another approach to the dreaded PHP_INCOMPLETE_CLASS problem:
<?php
class Includer {
static private $instance;
private $includePaths = array();
private $hasChanged = false;
public function instance() {
if (empty(self::$instance))
self::$instance = new Includer(INCLUDE_PATH_CACHE);
return self::$instance;
}
private function __construct($cacheFile) {
if (file_exists($cacheFile))
$this->includePaths = unserialize(file_get_contents($cacheFile));
}
static public function isCached($className) {
return (isset(self::instance()->includePaths[$className])) ? true : false;
}
static public function getPath($className) {
return (self::isCached($className)) ? self::instance()->includePaths[$className] : null;
}
static public function doInclude($class, $required = false) {
$className = substr($class, strrpos($class, '.')+1);
$path = str_replace('.', '/', $class) .'.php';
if (!isset(self::instance()->includePaths[$className]) or self::instance()->includePaths[$className] != $path) {
self::instance()->includePaths[$className] = $path;
self::instance()->hasChanged = true;
}
return ($required) ? require_once $path : include_once $path;
}
public function __destruct() {
if (self::instance()->hasChanged)
file_put_contents(INCLUDE_PATH_CACHE, serialize(self::instance()->includePaths));
}
}
?>
It has the smell of a workaround but I think it is a rather clean one. And here is a simple __autoload function for use with Includer:
<?php
function __autoload($className) {
if (Includer::isCached($className))
include_once Includer::getPath($className);
else
trigger_error('Cannot find '. $className, E_USER_ERROR);
}
?>
Of course you can extend that function to use other loading mechanisms if Includer::isCached() returns false. Also please note, that in the above implementation INCLUDE_PATH_CACHE has to the full path to a web server writable file.
The inline documentation is shortened a bit. The complete file is on http://ng.nerdking.de/static/php/Includer.phps
Cheers,
Niels
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" (manual/en/ini.core.php)
steven at gandso dot com
07-Mar-2006 12:10
An alternative to __autoload for PHP4.
<?php
$string = "";
foreach( glob( $_SERVER['DOCUMENT_ROOT'] . "/classes/class.*.inc" ) as $filename )
{
require_once( $filename );
if( preg_match( "/class\\.(.+?)\\.inc/", $filename, $className ) )
{
$string .= "$" . $className[1] . " = new " . ucfirst( $className[1] ) . ";";
}
}
eval( $string );
?>
unspammable-iain at iaindooley dot com
06-Feb-2006 06:44
in response to the post by UNSPAMMABLEkai at kaiundina dot de, i have another interesting implementation of the __autoload() system.
i have all my classes in their own file, where ThisClassName would be in the file this_class_name.class.php (Ruby inspired :-)
i really like having all class dependencies at the top of the class file, because you can tell at a glance what packages/classes a particular class uses/depends on, but this meant big loading times for huge class heirarchies, even if all those classes were not being used.
so i created my own require function that uses a serialised array of include paths, and then an __autoload() function that will get the required included path when it is needed _only_. this also allows for nice and liberal directory structures.
Here is the file with all the implementation in it:
<?
@$contents = file_get_contents('managed_code/includes.php');
if($contents)
$include_paths = unserialize($contents);
else
$include_paths = array();
function __autoload($class)
{
if($path = rsIncludePath($class))
require_once($path);
else
{
echo('You need to call rsRequire() before using a class: '.$class);
debug_print_backtrace();
}
}
function rsIncludePath($class)
{
global $include_paths;
$ret = '';
if(isset($include_paths[$class]))
$ret = $include_paths[$class];
return $ret;
}
function rsRequire($class,$required = true)
{
global $include_paths;
$classname = rsClassName($class);
$path = preg_replace('/\./','/',rsClasstoFile($class));
$path .= '.class.php';
if((!file_exists('packages/'.$path)))
{
echo('couldn\'t load package: '.$class.'<br /><br />
');
if($required)
debug_print_backtrace();
}
else
{
$path = 'packages/'.$path;
if(isset($include_paths[$classname]))
{
if($include_paths[$classname]!=$path)
{
$include_paths[$classname] = $path;
rsPersist();
}
}
else
{
$include_paths[$classname] = $path;
rsPersist();
}
}
}
function rsClassName($class)
{
$split = preg_split('/\./',$class);
$class_name = $split[count($split)-1];
return $class_name;
}
function rsPersist()
{
global $include_paths;
$data = serialize($include_paths);
file_put_contents('managed_code/includes.php',$data);
}
?>
Now here is a class file:
<?
rsRequire('package.name.SomeBaseClass');
rsRequire('package.name.MightNotBeUsed');
class ThisClass extends SomeBaseClass
{
}
?>
the class file for MightNotBeUsed would only be included if it was actually used in the class code. Also, notice that the above method is quite efficient because it only unserialises the array of include paths once, and will only reserialise the array in the case that it is a new include path, or the include path has changed. Also notice that this is 'session safe', meaning if you register a session object and then your application dies, you will not get class non-existing errors the next time you run it because the include paths are serialised as they are added. Enjoy!
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:)
info at tobiasdemuth dot de
03-Nov-2005 01:02
Hey there,
I've published c^2, an autoloading-system with self-modificating cache and directory crawler under www.tobias-demuth.de.
License is LGPL - just include it and don't think about class-inclusion anymore!
kind regards
Tobias
shurikk at gmail dot com
06-Oct-2005 02:33
one more thing about my previous example/comment (there is a bug :) )
--- file a.php should be like this
<?php
class A {
public $a;
function __construct($a) {
$this->a = $a;
}
public function getClassFile() {
return __FILE__;
}
}
?>
--- end a.php
one more file to test the example
--- b1.php
<?php
include('Session.php');
$a = new A();
$a = Session::put('a', $a);
?>
--- end b1.php
open b1.php, and then b.php in your browser.
in the Session class you might want to implement remove() method.
thanks
--alex
shurikk at gmail dot com
06-Oct-2005 01:31
somebody might find this "quick and dirty" example useful (see the code below). BTW, is there a magic metod that tells you what the class file name is? If none, perhaps a feature request?
What this example about: store objects in the session and restore them without worry of what external files to be "required" (solves the problem when you get incomplete PHP object, when your class is not declared prior unserialize())
PHP5, but easy to adapt for PHP4
--- file Session.php
<?php
session_start();
class Session {
public static function has($name) {
return isset($_SESSION[$name]);
}
public static function get($name) {
if(Session::has($name)) {
if(Session::has('__requireFiles')) {
$requireFiles = unserialize($_SESSION['__requireFiles']);
if(array_key_exists($name, $requireFiles)) {
require_once($requireFiles[$name]);
}
}
return unserialize($_SESSION[$name]);
}
return null;
}
public static function put($name, $value) {
if(is_object($value)) {
if(method_exists($value, 'getClassFile')) {
if(!($requireFiles = Session::get('__requireFiles')))
$requireFiles = array();
$requireFiles[$name] = $value->getClassFile();
Session::put('__requireFiles', $requireFiles);
}
}
$_SESSION[$name] = serialize($value);
}
}
?>
--- end Session.php
--- file a.php
<?php
include('Session.php');
class A {
public $a;
function __construct($a) {
$this->a = $a;
}
public function getClassFile() {
return __FILE__;
}
}
$a = new A('test');
Session::put('a', $a);
}
?>
--- end a.php
--- file b.php
<?php
include('Session.php');
$a = Session::get('a');
?>
--- end b.php
kai at kaiundina dot de
20-Sep-2005 12:34
To: gomasj at gmail dot com
I strongly disagree in that "no well organized programmer will need to use it".
The method reduces the overhead when loading unneeded classes while encouraging the use of well organized class libraries.
Assume you have a class needing an undetermined number of other classes to operate properly - let's say an XML-parser that parses a document into an object tree (one class per element is a typical procedure).
A common behavior was to load all possibly needed classes in advance - regardless if they would be used ever. That would be a performance deasaster for the above case.
Another possibility was to load the particular class when needed - providing a path to the file containing the class declaration. Since relative path's in PHP are calculated relative to the script handling the client request, they're some kind of complex to manage in huge projects, where the script can be called from various locations.
If you're willing to move a class's declaration file to another location (directory) you have to update each reference to that file.
Lot's of well organized programmers (so are you), wrote their own mechanisms so solve these problems. But you always had to make at least one call to load the class file each time it might possibly be referenced for the first time in code execution - that are:
- new
- extends
- implements
- Type hints
- static reference (class::xxx)
- deserialization of sessions
__autoload() simply provides an event handler to centralize the loading of a class's declaration only when it's needed for the first time. Regardless where or by what the request occurred.
So it keeps your code clean, fast and allows you to reorganize your class-library as you like without modifying any of your source files (except the autoload-function itself).
We use the autoload feature in a 200,000 lines php-project as follows:
The 'ClassManager' maintains a cache file containing the file paths to each class-declaration. Whenever an unknown class (not present in the cache, yet) is requested, it searches the directories for a file containing the desired class declaration and adds it to the cache for the next time. This method allows us to modify our class-library at will. We can add, move or remove classes without adjusting a single line of code. When our software starts up, the ClassManager has to handle about 6,000 class requests - without having to worry about performance reasons.
I am developer and project manager in the project mentioned above (a web based cms) - so I'd call myself well organized.
Anyway,
thanks for your opinion
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
class MyClass
{
public static function _construct()
{
echo '<div>static constructor</div>';
}
public function __construct()
{
echo '<div>dynamic constructor</div>';
}
}
?>
Content of index.php5:
<?php
function __autoload($aClassName)
{
require_once ($aClassName . '.class.php5');
$staticConstructorReference = array($aClassName, '_construct');
if (is_callable($staticConstructorReference))
{
call_user_func($staticConstructorReference);
}
}
$article = new MyObject();
?>
andy bravery
16-Sep-2005 02:37
kencomer, I think there is a problem with your function below in that if strpos() or stripos() locate your class name at the beginning of the filename string then they return a position 0 which gets interpretted as a boolean FALSE. For me this meant my file was never found.
kencomer at NOSPAM dot kencomer dot com
14-Sep-2005 06:46
Yet another class/interface __autoload function. Includes an example usage of the SPL DirectoryIterator class, a settable case-ignore flag, and support for multiple file name patterns to allow easy integration from multiple sources.
<?php
define('IGNORE_CASE',true);
function __autoload($class_name) {
static $possible_path = NULL;
static $permitted_formats = array(
"&CLASS.class.inc"
,"&CLASS.class.inc.php"
,"&CLASS.class.inc.php5"
,"class.&CLASS.inc"
,"class.&CLASS.inc.php"
,"class.&CLASS.inc.php5"
,"&CLASS.interface.inc"
,"&CLASS.interface.inc.php"
,"&CLASS.interface.inc.php5"
,"i&CLASS.interface.inc"
,"i&CLASS.interface.inc.php"
,"i&CLASS.interface.inc.php5"
);
if (NULL===$possible_path):
$possible_path = array_flip(array(
"."
,".."
,"../include"
,"/public_html/php/include"
));
$possible_path = array_keys(array_merge($possible_path,
array_flip(explode(ini_get("include_path"),";"))));
endif; $possibility = str_replace("&CLASS",$class_name,$permitted_formats);
foreach ( $possible_path as $directory ) {
if (!file_exists($directory) or !is_dir($directory))
{
continue;
}
$file_to_check = new DirectoryIterator($directory);
foreach ( $file_to_check as $file ) {
if ( !$file->isDir()
and ( defined(IGNORE_CASE) && TRUE===IGNORE_CASE )
? stripos($file->getFileName(),$class_name)
: strpos($file->getFileName(),$class_name) ) :
foreach ( $possibility as $compare ):
if ((defined(IGNORE_CASE) && TRUE===IGNORE_CASE )
? !strcasecmp($compare,$file->getFileName())
: $compare===$file->getFileName()
) {
include_once($compare);
return TRUE;
}
endforeach; endif;
} }
}
?>
sr at brightlight dot ch
25-Jul-2005 02:52
If you want to autoload functions you can do this with a little work-around:
<?php
class utilities
{
protected static $instance;
protected function __construct()
{
}
public function get()
{
if (isset(self::$instance)) {
return self::$instance;
} else {
self::$instance = new utilities();
return self::$instance;
}
}
public function __call($function, $arguments)
{
if (!function_exists($function)) {
include_once("function.$function.inc");
}
return call_user_func_array($function, $arguments);
}
}
utilities::get()->someFunction(...); ?>
Unfortunately __call() is only invoked when the method is accessed via -> and not via ::.
sr at brightlight dot ch
30-Jun-2005 09:43
I hope this helps some people:
<?php
function __autoload($name) {
$class = $interface = false;
if (include_exists("interface.$name.inc")) {
include_once("interface.$name.inc");
$interface = true;
}
if (include_exists("class.$name.inc")) {
include_once("class.$name.inc");
$class = true;
}
if ($class === false && $interface === false) {
trigger_error("Failed to include class/interface $name", E_USER_WARNING);
return false;
}
return true;
}
function include_exists($file)
{
static $include_dirs = null;
static $include_path = null;
if (is_null($include_dirs) || get_include_path() !== $include_path) {
$include_path = get_include_path();
foreach (split(PATH_SEPARATOR, $include_path) as $include_dir) {
if (substr($include_dir, -1) != '/') {
$include_dir .= '/';
}
$include_dirs[] = $include_dir;
}
}
if (substr($file, 0, 1) == '/') { return (file_exists($file));
}
if ((substr($file, 0, 7) == 'http://' || substr($file, 0, 6) == 'ftp://') && ini_get('allow_url_fopen')) {
return true;
}
foreach ($include_dirs as $include_dir) {
if (file_exists($include_dir.$file)) {
return true;
}
}
return false;
}
?>
christopher dot klein at ecw dot de
26-Jun-2005 11:20
Sometimes you could get in trouble, if you have already written a management-class for an object, but you still don not have designed the object.
For example you have created a class called Management_FileObject:
<?php
class Management_FileObject
{
private static $objFile;
public static function getInstance()
{
if (!is_object(self::$objFile))
{
self::$objFile = new FileObject();
}
return self::$objFile;
}
public static function writeData($data)
{
self::getInstance()->setData($data);
}
public static function readData()
{
return self::getInstance()->getData();
}
}
?>
The object FileObject is still not defined (why-ever).
Now we can use a method, which I want to name "Extreme Prototyping". Redefine the __autoload()-function:
<?php
function __autoload($className)
{
$arrPath = array('../classes/');
for ($i = 0, $m = sizeof($arrPath); $i < $m; $i++)
{
$phpFile = $arrPath[$i].$className.".php5";
if (file_exists($phpFile))
{
include_once($phpFile);
return true;
}
}
$str = 'class '.$className.'
{
private static $objInstances = array();
public function __construct()
{
self::$objInstances[] = $this;
}
private $objVals = array();
public function __call($m, $a)
{
if (preg_match("/^(set|get)(.*)/",$m,$arrRet))
{
if ($arrRet[1] == "get")
{
if ($this->objVals[$arrRet[2]])
{
return $this->objVals[$arrRet[2]];
}
}
else
{
$this->objVals[$arrRet[2]] = $a[0];
return true;
}
}
}
public function dumpVar()
{
var_dump($this);
}
public static function dumpObjects()
{
var_dump(self::$objInstances);
}
}';
eval($str);
}
?>
Now you can test the code above with this lines:
<?php
$testData = "Extreme Prototyping success";
Management_FileObject::writeData($testData);
if ($testData != ($returnData = Management_FileObject::readData()))
{
print "Extreme Prototyping falied.";
}
else
{
print "Got ".$returnData;
}
?>
I hope, you find this usefull.
Best regards,
Christopher Klein
PrzemekG_ at poczta dot onet dot pl
15-Jun-2005 03:27
This is a little more usefull code (modified from nhartkamp at eljakim dot N0SP4M dot nl)
<?php
function __autoload ($class_name) {
$file = 'system/objects/' . $class_name . '.inc.php';
if (!file_exists ($file)) {
return eval ("class $class_name {" .
" function $class_name ($a=0, $b=0, $c=0, $d=0, $e=0, $f=0, $g=0, $h=0, $i=0) {" .
" throw new Exception ();" .
" }" .
"}");
}
require_once ($file);
}
?>
Adding some arguments to the constructor will prevent errors about argument count.
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(); ?>
Works with multiple session objects as well. Tested on a Win2k/IIS machine.
erikzoltan NOSPAM at comcast dot net
06-Apr-2005 07:41
When using __autoload you'll have one class in each file. I have developed the habit of placing a UML class diagram at the top of each file. It's extremely helpful when you start to work with a large number of classes, especially if you're part of a team. And it's easy to do.
<?php
class MyExample extends SomethingElse
{
public $FirstProperty;
public $SecondProperty = array();
private $ThirdProperty;
public __constructor()
{
}
public static function ClassMethod($a, $b, $c)
{
return $a+$b+$c;
}
public function DoSomething()
{
}
private function SomethingElse()
{
}
}
?>
Of course you have to maintain the UML comments along with your classes. (I'm planning to use reflection to automate this process in the future so that issue will soon disappear.)
El Lobo
17-Mar-2005 05:10
function autoloadwrapper($parameter='',$register=false) {
static $function='default_function';
if( $register ){
$function=$parameter;
return true;
}
if( ! is_array($parameter) ){
$param[]=$parameter;
}else{
$param&=$parameter;
}
if( function_exists( $function ) ){
return @call_user_func_array( $function,$param );
}else{
$methode=explode("::",$function);
return @call_user_func_array( $methode,$param );
}
}
function __autoload($class_name) {
return autoloadwrapper( $class_name );
}
Simple hack to switch between different __autoload-functions.
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
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.
Jami Pekkanen
17-Jan-2005 04:27
Autoloading can be abused to simulate C++-style templates:
<?php
function __autoload($className)
{
$names = explode('__', $className, 2);
if(count($names) != 2) return;
eval(
"class $className extends {$names[0]}
{
public static function getTemplateValue()
{
return {$names[1]};
}
}"
);
}
class Dummy {}
echo Dummy__HelloWorld::getTemplateValue()."\n"; $bye = new Dummy__ByeBye();
echo $bye->getTemplateValue()."\n"; ?>
Also a great way to confuse anyone trying to read/maintain your code.
smith at backendmedia dot com
04-Jan-2005 07:45
It seems that __autoload() works both for classes and interfaces.
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
| |