note 66162 deleted from language.oop5.autoload by felipe

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

« previous php.notes (#137499) next »