* @version 1.1
* @copyright Copyright(c) 2007, 2008 Roland Haeder, this is free software
* @license GNU GPL 3.0 or any newer version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
class ClassLoader {
/**
* Configuration array
*/
private $cfg = array();
/**
* An ArrayObject for found classes
*/
private $classes = null;
/**
* Suffix with extension for all class files
*/
private $prefix = "class_";
/**
* Suffix with extension for all class files
*/
private $suffix = ".php";
/**
* Length of the suffix. Will be overwritten later.
*/
private $sufLen = 0;
/**
* Length of the prefix. Will be overwritten later.
*/
private $preLen = 0;
/**
* A list for directory names (no leading/trailing slashes!) which not be scanned by the path scanner
* @see scanLocalPath
*/
private $ignoreList = array();
/**
* An ArrayList object for include directories
*/
private $dirList = null;
/**
* Debug this class loader? (true = yes, false = no)
*/
private $debug = false;
/**
* Counter for scanned directories (debug output)
*/
private $dirCnt = 0;
/**
* Counter for loaded classes (debug output)
*/
private $classCnt = 0;
/**
* Instance of this class
*/
private static $thisInstance = null;
/**
* The *public* constructor
*
* @param $cfgInstance Configuration class instance
* @return void
*/
public function __construct (FrameworkConfiguration $cfgInstance) {
// Init the array list
$this->dirList = new ArrayObject();
// Set suffix and prefix from configuration
$this->suffix = $cfgInstance->readConfig("class_suffix");
$this->prefix = $cfgInstance->readConfig("class_prefix");
// Estimate length of prefix and suffix for substr() function (cache)
$this->sufLen = strlen($this->suffix);
$this->preLen = strlen($this->prefix);
// Set configuration instance
$this->cfgInstance = $cfgInstance;
// Initialize the classes list
$this->classes = new ArrayObject();
// Set own instance
self::$thisInstance = $this;
}
/**
* Getter for an instance of this class
*
* @return $thisInstance An instance of this class
*/
public final static function getInstance () {
return self::$thisInstance;
}
/**
* Scans recursively a local path for class files which must have a prefix and a suffix as given by $this->suffix and $this->prefix
*
* @param $basePath The relative base path to PATH constant for all classes
* @param $ignoreList An optional list (array or string) of directory names which shall be ignored
* @return void
*/
public function loadClasses ($basePath, $ignoreList = array() ) {
// Convert string to array
if (!is_array($ignoreList)) $ignoreList = array($ignoreList);
// Directories which our class loader ignores by default while
// deep-scanning the directory structure. See scanLocalPath() for
// details.
$ignoreList[] = ".";
$ignoreList[] = "..";
$ignoreList[] = ".htaccess";
// Keep it in class for later usage
$this->ignoreList = $ignoreList;
// Set base directory which holds all our classes, we should use an
// absolute path here so is_dir(), is_file() and so on will always
// find the correct files and dirs.
$basePath2 = realpath($basePath);
// If the basePath is false it is invalid
if ($basePath2 === false) {
// TODO: Do not die here.
die("Cannot read {$basePath} !");
} else {
// Set base path
$basePath = $basePath2;
}
// Load all super classes (backward, why ever this name... :-? )
// We don't support sub directories here...
$this->scanLocalPath($basePath);
// While there are directories in our list scan them for classes
$cnt = 0;
while ($cnt != $this->dirList->count()) {
for ($idx = $this->dirList->getIterator(); $idx->valid(); $idx->next()) {
// Get current path
$currPath = $idx->current();
// Remove the current entry or else this will lead into a infinite loop
$this->dirList->offsetSet($idx->key(), "");
// Scan the directory
$this->scanLocalPath($currPath);
}
// Check if we can leave
$cnt = 0;
for ($idx = $this->dirList->getIterator(); $idx->valid(); $idx->next()) {
if ($idx->current() == "") $cnt++;
}
}
}
/**
* The local path scanner. A found class will be loaded immediately
* @param $localPath The local path which shall be recursively scanned for include files
* @return void
*/
private function scanLocalPath ($localPath) {
// Empty path names will be silently ignored
if (empty($localPath)) return;
// TODO: No dies here, mayybe this should be rewritten to throw an exception?
$dirInstance = FrameworkDirectoryPointer::createFrameworkDirectoryPointer($localPath);
while ($dirClass = $dirInstance->readDirectoryExcept($this->ignoreList)) {
// We need the relative dir name as an array index some lines below
$dirClass2 = $dirClass;
// A nice replacement for a simple dot ;)
$dirClass = sprintf("%s/%s", $localPath, $dirClass);
// Is a readable file with configured prefix and suffix? All other
// files will silently be ignored!
//* DEBUG: */ print "Prefix=".$this->prefix."(".substr($dirClass2, 0 , $this->preLen).")\n";
//* DEBUG: */ print "Suffix=".$this->suffix."(".substr($dirClass2, -$this->sufLen, $this->sufLen).")\n";
//* DEBUG: */ print "ENTRY={$dirClass}\n";
if (
(is_file($dirClass))
&& (is_readable($dirClass))
&& (substr($dirClass2, 0 , $this->preLen) == $this->prefix)
&& (substr($dirClass2, -$this->sufLen, $this->sufLen) == $this->suffix)
) {
// Class found so load it instantly
//* DEBUG: */ print "CLASS={$dirClass}\n";
$this->classes->append($dirClass);
$this->classCnt++;
} elseif (is_dir($dirClass) && !in_array($dirClass2, $this->ignoreList)) {
// Directory found and added to list
//* DEBUG: */ print "DIR={$dirClass}\n";
if ($dirClass2 == "interfaces") {
$this->scanLocalPath($dirClass);
} else {
$this->dirList->append($dirClass);
}
$this->dirCnt++;
}
//* DEBUG: */ print "LOOP!\n";
} // END - while
// Close directory handler
$dirInstance->closeDirectory();
// Output counter in debug mode
if (defined('DEBUG_MODE')) print(sprintf("[%s:] %d Klassendateien in %d Verzeichnissen gefunden und geladen.
\n",
__CLASS__,
$this->classCnt,
$this->dirCnt
));
}
/**
* Includes all found classes
* @return void
*/
public function includeAllClasses () {
if (is_object($this->classes)) {
// Load all classes
for ($idx = $this->classes->getIterator(); $idx->valid(); $idx->next()) {
// Load current class
//* DEBUG: */ print "Class=".$idx->current()."\n";
require_once($idx->current());
}
// Re-initialize the classes list
$this->classes = new ArrayObject();
}
}
}
// Initial load of core classes and the FrameworkDirectoryPointer class
require_once(sprintf("%sinc/classes/interfaces/class_FrameworkInterface%s", PATH, FrameworkConfiguration::getInstance()->readConfig("php_extension")));
require_once(sprintf("%sinc/classes/main/class_BaseFrameworkSystem%s", PATH, FrameworkConfiguration::getInstance()->readConfig("php_extension")));
require_once(sprintf("%sinc/classes/main/io/class_FrameworkDirectoryPointer%s", PATH, FrameworkConfiguration::getInstance()->readConfig("php_extension")));
// Initialize the class loader
$loader = new ClassLoader(FrameworkConfiguration::getInstance());
// [EOF]
?>