<?php
/**
* @package util
**/
/**
* ClassLoader.
*
* Provides a way of loading only the classes required by a given file in a Java-esque 'import' type way.
*
* Usage is as follows:
*
* <code>
* ClassLoader::import('packageName.className');
* </code>
*
* @package util
* @version 0.1
* @author Alex Potsides, {@link http://www.achingbrain.net http://www.achingbrain.net}
* @copyright Alex Potsides, {@link http://www.achingbrain.net http://www.achingbrain.net}
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class ClassLoader
{
public static $classPath = '/inc/packages/';
private static $loadAttempts = 0;
private static $loadedClasses = array();
private static $loadedFiles = array();
/**
* A private constructor so we cannot be instantiated
*/
private function __construct()
{
}
/**
* Loads a class or package
*
* @param $className string package.className or package.*
*/
public static function import($className)
{
ClassLoader::$loadAttempts++;
if(isset(ClassLoader::$loadedClasses[$className])) // have already tried to load this one
{
return;
}
// make sure we do not proccess a request for the requested class again
ClassLoader::$loadedClasses[$className] = true;
// look for * as last character to match 'packageName.*''
if(substr($className, strlen($className) - 1) == '*')
{
ClassLoader::loadPackage($className);
return;
}
$path = ClassLoader::getPath($className);
$pathArr = explode('/', $path);
$actualClassName = $pathArr[count($pathArr) -1];
$path = substr($path, 0, strlen($path) - strlen($actualClassName));
ClassLoader::getFileFromDirectory($path, false, $actualClassName);
}
/**
* Returns the number of classes that have been loaded
*
* @return int The number of classes that have been loaded
*/
public static function getClassesLoaded()
{
return count(ClassLoader::$loadedFiles);
}
/**
* Returns the number of times classes have been loaded
*
* @return int The number of times classes have been loaded
*/
public static function getLoadAttempts()
{
return ClassLoader::$loadAttempts;
}
/**
* Loads a whole directory of *.php files
*/
private static function loadPackage($packageName)
{
$path = ClassLoader::getPath(substr($packageName, 0, -1));
ClassLoader::getFileFromDirectory($path);
}
/**
* Attempts to open a directory and either match the passed class name to a file name or load the whole lot
*/
private static function getFileFromDirectory($directoryPath, $multiple = true, $className = null)
{
try
{
$dir = new DirectoryIterator($directoryPath);
foreach ($dir as $file)
{
$fileName = $dir->getFilename();
/*
* If the class name is not null and the beginning of the file name matches the classname
* - eg. to find DatabaseConnection.class.php or DatabaseConnection.interface.php
*
* or
*
* The class name is null and the last three letters of the file name are 'php' - eg to find *.php
*/
if((!is_null($className) && (substr($fileName, 0, strlen($className)) == $className)) || (is_null($className)) && substr($fileName, strlen($fileName) - 3, 3) == 'php')
{
$filePath = $directoryPath . $fileName;
if(!isset(ClassLoader::$loadedFiles[$filePath]))
{
/* add to the array first, otherwise the included file could request itself
* - eg. if it tries to load all of its own package
*/
ClassLoader::$loadedFiles[$filePath] = true;
include($filePath);
}
if($multiple === false) // in single file mode and we have our file, get out
{
return;
}
}
}
}
catch(exception $e)
{
// need to do something better here
echo '<h1>Error loading class</h1><p>' . $e->getMessage() . '</p>';
exit;
}
}
/**
* Turns database.DatabaseConnection into database/DatabaseConnection, ready to have .class.php or whatever added to the end of it
*/
private static function getPath($path)
{
return $_SERVER['DOCUMENT_ROOT'] . ClassLoader::$classPath . str_replace('.', '/', $path);
}
}
?>