<?php
 
/**
 
 *
 
 * @author Andrei Alexandru Romila
 
 * @version 1.0
 
 *        
 
 */
 
class Autoloader {
 
    
 
    /**
 
     * PHP default file extension
 
     * 
 
     * @var string
 
     */
 
    const PHP_EXTENSION = '.php';
 
 
    /**
 
     * Stores all namespaces and directories
 
     * 
 
     * @var array
 
     */
 
    protected $prefixes = array();
 
    
 
    /**
 
     * Stores all the files 
 
     * 
 
     * @var array
 
     */
 
    protected $files = array();
 
 
    /**
 
     * 
 
     * @param boolean $register
 
     */
 
    public function __construct($register = false) {
 
        if ($register === true) {
 
            $this->registerAutoloader();
 
        }
 
    }
 
 
    /**
 
     * Registers a new autoloader funtion
 
     * 
 
     * @return boolean Returns true on success or false on failure.  
 
     */
 
    public function registerAutoloader() {
 
        return spl_autoload_register(array($this, 'loadClass'), false, true);
 
    }
 
    
 
    /**
 
     * Register a new file for a classname.
 
     * 
 
     * @param string $class The name of the class
 
     * @param string $filename The filename
 
     * @param boolean $replace If the class is already register, replace the filename
 
     */
 
    public function registerFile($class, $filename, $overwrite = false) {
 
        
 
        if (is_file($filename) === false || is_readable($filename) === false) {
 
            echo 'The file: ' . $filename . ' doen\'t exist or is not readable!<br />';
 
            return;
 
        }
 
        
 
        // Remove the '\' if the class is \ClassName
 
        $class = rtrim($class, '\\');
 
        
 
        // Get real path of the file and normalize directory separator
 
        $filename = realpath($filename);
 
        $filename = str_replace('\\', '/', $filename);
 
        
 
        // If is not set yet, create it
 
        if (isset($this->files[$class]) === false) {
 
            
 
            $this->files[$class] = $filename;
 
            
 
        } else if ($overwrite === true) {
 
            
 
            // Overwrite the last filename
 
            $this->files[$class] = $filename;
 
            
 
        }
 
    }
 
 
    /**
 
     * Registers a new namespace in the loader
 
     * 
 
     * @param string $namespace The namespace
 
     * @param string $directory Path to the namespace
 
     */
 
    public function registerNamespace($namespace, $directory, $prepend = false) {
 
    
 
        if (is_dir($directory) === false || is_readable($directory) === false) {
 
            echo 'The directory: ' . $directory . ' doen\'t exist or is not readable!<br />';
 
            return;
 
        }
 
        
 
        $namespace = trim($namespace, '\\') . '\\';
 
        $directory = realpath($directory);
 
        $directory = str_replace('\\', '/', $directory) . '/';
 
    
 
        // If doesnt exist create a new array for the namespace.
 
        if (false === isset($this->prefixes[$namespace])) {
 
            
 
            $this->prefixes[$namespace] = array();
 
            
 
        } else if (in_array($directory, $this->prefixes[$namespace], true)) {
 
            
 
            // Already added ...
 
            return;
 
        
 
        }
 
    
 
        if ($prepend === true) {
 
            // Prepend this namespace
 
            $this->prefixes[$namespace] = array_unshift($this->prefixes[$namespace], $directory);
 
        } else {
 
            // A bit faster than array_push($array, $value1)
 
            $this->prefixes[$namespace][] = $directory;
 
        }
 
        
 
    }
 
    
 
    /**
 
     * PSR4 loadClass function with some enhancements.
 
     * 
 
     * @param string $class
 
     */
 
    public function loadClass($class) {
 
        
 
        // Check for direct file registration - a bit faster than searching in a sub folder
 
        if (isset($this->files[$class]) && $this->requireFile($this->files[$class])) {
 
            return $this->files[$class];
 
        }
 
        
 
        // the current namespace prefix
 
        $prefix = $class;
 
        
 
        // work backwards through the namespace names of the fully-qualified
 
        // class name to find a mapped file name
 
        while (false !== ($position = strrpos($prefix, '\\'))) {
 
        
 
            // retain the trailing namespace separator in the prefix
 
            $prefix = substr($class, 0, $position + 1);
 
        
 
            // the rest is the relative class name
 
            $relative = substr($class, $position + 1);
 
        
 
            // try to load a mapped file for the prefix and relative class
 
            $filename = $this->loadFile($prefix, $relative);
 
            if ($filename) {
 
                return $filename;
 
            }
 
        
 
            // remove the trailing namespace separator for the next iteration
 
            // of strrpos()
 
            $prefix = rtrim($prefix, '\\');
 
        }
 
        
 
        // never found a mapped file
 
        return false;
 
        
 
    }
 
    
 
    /**
 
     * Load the mapped file for a namespace prefix and relative class.
 
     *
 
     * @param string $prefix The namespace prefix.
 
     * @param string $relativePath The relative class name.
 
     * @return mixed Boolean false if no mapped file can be loaded, or the
 
     * name of the mapped file that was loaded.
 
     */
 
    protected function loadFile($prefix, $relativePath) {
 
        
 
        // are there any base directories for this namespace prefix?
 
        if (isset($this->prefixes[$prefix]) === false) {
 
            return false;
 
        }
 
    
 
        // look through base directories for this namespace prefix
 
        foreach ($this->prefixes[$prefix] as $directory) {
 
            
 
            $filename = $directory . str_replace('\\', '/', $relativePath) . self::PHP_EXTENSION;
 
    
 
            // if the mapped file exists, require it
 
            if ($this->requireFile($filename)) {
 
                return $filename;
 
            }
 
        }
 
    
 
        // never found it
 
        return false;
 
    }
 
    
 
    /**
 
     * If a file exists, require it from the file system.
 
     *
 
     * @param string $file The file to require.
 
     * @return bool True if the file exists, false if not.
 
     */
 
    protected function requireFile($filename) {
 
        
 
        if (is_readable($filename)) {
 
            require $filename;
 
            return true;
 
        }
 
        
 
        return false;
 
    }
 
    
 
}
 
 
 |