Skip to content

Instantly share code, notes, and snippets.

@WinterSilence
Created April 30, 2016 21:44
Show Gist options
  • Save WinterSilence/0ecf669c4cfffdad5050c3d14f68b17c to your computer and use it in GitHub Desktop.
Save WinterSilence/0ecf669c4cfffdad5050c3d14f68b17c to your computer and use it in GitHub Desktop.
<?php
/**
* A general-purpose implementation that includes the optional functionality
* of allowing multiple base directories for a single namespace prefix.
*/
class Psr4Autoloader
{
const EXTENSION = '.php';
/**
* An associative array where the key is a namespace prefix and the value
* is an array of base directories for classes in that namespace.
*
* @var array
*/
protected $prefixes = [];
/**
* Register loader with SPL autoloader stack.
*
* @param bool $prepend If true, will prepend the autoloader on
* the autoload queue instead of appending it.
* @return $this
*/
public function register($prepend = false)
{
spl_autoload_register([$this, 'loadClass'], true, $prepend);
return $this;
}
/**
* Unregister loader with SPL autoloader stack.
*
* @return void
*/
public function unregister()
{
spl_autoload_unregister([$this, 'loadClass']);
}
/**
* Adds a base directory for a namespace prefix.
*
* @param string $prefix The namespace prefix.
* @param string $baseDir A base directory for class files in the namespace.
* @param bool $prepend If true, prepend the base directory to the stack.
* instead of appending it, this causes it to be searched first rather than
* last.
* @return this
*/
public function addPrefix($prefix, $baseDir, $prepend = false)
{
// Normalize namespace prefix.
$prefix = trim($prefix, '\\') . '\\';
// Normalize the base directory with a trailing separator.
$baseDir = realpath($baseDir) . DIRECTORY_SEPARATOR;
// Initialize the namespace prefix array.
if (!isset($this->prefixes[$prefix])) {
$this->prefixes[$prefix] = [];
}
// Retain the base directory for the namespace prefix.
if ($prepend) {
array_unshift($this->prefixes[$prefix], $baseDir);
} else {
array_push($this->prefixes[$prefix], $baseDir);
}
return $this;
}
/**
* Loads the class file for a given class name.
*
* @param string $class The fully-qualified class name.
* @return bool
*/
public function loadClass($class)
{
if (strpos($class, '\\') !== false) {
foreach ($this->prefixes as $namespace => $baseDirs) {
if (strpos($class, $namespace) === 0) {
$path = substr($class, strlen($namespace));
$path = str_replace('\\', DIRECTORY_SEPARATOR, $path) . self::EXTENSION;
foreach ($baseDirs as $baseDir) {
$file = $baseDir . $path;
// If the mapped file exists, require it
if ($this->requireFile($file)) {
return $file;
}
}
}
}
}
// Never found a mapped file
return false;
}
/**
* If a file exists, require it from the file system.
*
* @param string $file The file to require.
* @return bool
*/
protected function requireFile($file)
{
if (file_exists($file)) {
require $file;
return true;
}
return false;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment