note 66162 deleted from language.oop5.autoload by felipe
| From: | felipe@php.net | Date: | Mon, 24 Mar 2008 22:34:37 +0000 |
| Subject: | note 66162 deleted from language.oop5.autoload by felipe | ||
| References: | 1 | Groups: | php.notes |
| Request: | Send a blank email to php-notes+get-137499@lists.php.net to get a copy of this message | ||
Note Submitter: phpman at generic dot depoll dot de
----
"Inspired" by unspammable-iain at iaindooley dot com, here is another approach to the
dreaded PHP_INCOMPLETE_CLASS problem:
<?php
/**
* Provides an include function which caches the path to a class in order to provide a better
autoload functionality.
*
* While the Includer::doInclude() function takes a a string as an argument, which includes path
information, __autoload() will
* always get a "naked" classname. In order to find the according path for that class, we
use our cache which essentially is a hash
* of the form array(className => filePath). The inevitable constraint of that approach is
obvious: we can't remember several
* pathes for one and the same classname, meaning that it either has to be unique or you have to
use several Includers for your
* different, but equally named, classes.
*
* @author "Niels Ganser" <phpman@generic.depoll.de>
*/
class Includer {
static private $instance;
private $includePaths = array();
private $hasChanged = false;
/**
* We use Singeltons here, so please use this function to get an Includer instance.
*
* @return Includer An instance of Includer. And only one.
*/
public function instance() {
if (empty(self::$instance))
self::$instance = new Includer(INCLUDE_PATH_CACHE);
return self::$instance;
}
/**
* @param string Path to the cache file. Obviously has to be read- and writable by the webserver
user.
*/
private function __construct($cacheFile) {
if (file_exists($cacheFile))
$this->includePaths = unserialize(file_get_contents($cacheFile));
}
/**
* Checks if the path to a class with the given name is cached.
*
* @param string $className Name of a class
* @return boolean
*/
static public function isCached($className) {
return (isset(self::instance()->includePaths[$className])) ? true : false;
}
/**
* Returns the cached path for the given classname or null if there is nothing cached.
*
* @param string $className Name of a class
* @return mixed A filepath (string) which we remember as leading to the given class or null if
we have
* no clue as to where to look for the class.
*/
static public function getPath($className) {
return (self::isCached($className)) ? self::instance()->includePaths[$className] : null;
}
/**
* Includes (or requires) a given class.
*
* @param string $class The path to our class in a package.className format.
* I.e. "classes.money.AUD" would lead to "classes/money/AUD.php".
* @param boolean $required If true, we require the file instead of just trying to include it.
* @return boolean Return value of the require_once resp. include_once statement.
*/
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;
}
/**
* Writes the cache to disk, if its contents have changed.
*/
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