2015-08-17 17:00:26 -07:00
< ? php
/*
* This file is part of Composer .
*
* ( c ) Nils Adermann < naderman @ naderman . de >
* Jordi Boggiano < j . boggiano @ seld . be >
*
* For the full copyright and license information , please view the LICENSE
* file that was distributed with this source code .
*/
namespace Composer\Autoload ;
/**
* ClassLoader implements a PSR - 0 class loader
*
* See https :// github . com / php - fig / fig - standards / blob / master / accepted / PSR - 0. md
*
* $loader = new \Composer\Autoload\ClassLoader ();
*
* // register classes with namespaces
* $loader -> add ( 'Symfony\Component' , __DIR__ . '/component' );
* $loader -> add ( 'Symfony' , __DIR__ . '/framework' );
*
* // activate the autoloader
* $loader -> register ();
*
* // to enable searching the include path (eg. for PEAR packages)
* $loader -> setUseIncludePath ( true );
*
* In this example , if you try to use a class in the Symfony\Component
* namespace or one of its children ( Symfony\Component\Console for instance ),
* the autoloader will first look for the class under the component /
* directory , and it will then fallback to the framework / directory if not
* found before giving up .
*
* This class is loosely based on the Symfony UniversalClassLoader .
*
* @ author Fabien Potencier < fabien @ symfony . com >
* @ author Jordi Boggiano < j . boggiano @ seld . be >
*/
class ClassLoader
{
// PSR-4
private $prefixLengthsPsr4 = array ();
private $prefixDirsPsr4 = array ();
private $fallbackDirsPsr4 = array ();
// PSR-0
private $prefixesPsr0 = array ();
private $fallbackDirsPsr0 = array ();
private $useIncludePath = false ;
private $classMap = array ();
private $classMapAuthoritative = false ;
public function getPrefixes ()
{
if ( ! empty ( $this -> prefixesPsr0 )) {
return call_user_func_array ( 'array_merge' , $this -> prefixesPsr0 );
}
return array ();
}
public function getPrefixesPsr4 ()
{
return $this -> prefixDirsPsr4 ;
}
public function getFallbackDirs ()
{
return $this -> fallbackDirsPsr0 ;
}
public function getFallbackDirsPsr4 ()
{
return $this -> fallbackDirsPsr4 ;
}
public function getClassMap ()
{
return $this -> classMap ;
}
/**
* @ param array $classMap Class to filename map
*/
public function addClassMap ( array $classMap )
{
if ( $this -> classMap ) {
$this -> classMap = array_merge ( $this -> classMap , $classMap );
} else {
$this -> classMap = $classMap ;
}
}
/**
* Registers a set of PSR - 0 directories for a given prefix , either
* appending or prepending to the ones previously set for this prefix .
*
* @ param string $prefix The prefix
* @ param array | string $paths The PSR - 0 root directories
* @ param bool $prepend Whether to prepend the directories
*/
public function add ( $prefix , $paths , $prepend = false )
{
if ( ! $prefix ) {
if ( $prepend ) {
$this -> fallbackDirsPsr0 = array_merge (
( array ) $paths ,
$this -> fallbackDirsPsr0
);
} else {
$this -> fallbackDirsPsr0 = array_merge (
$this -> fallbackDirsPsr0 ,
( array ) $paths
);
}
return ;
}
$first = $prefix [ 0 ];
if ( ! isset ( $this -> prefixesPsr0 [ $first ][ $prefix ])) {
$this -> prefixesPsr0 [ $first ][ $prefix ] = ( array ) $paths ;
return ;
}
if ( $prepend ) {
$this -> prefixesPsr0 [ $first ][ $prefix ] = array_merge (
( array ) $paths ,
$this -> prefixesPsr0 [ $first ][ $prefix ]
);
} else {
$this -> prefixesPsr0 [ $first ][ $prefix ] = array_merge (
$this -> prefixesPsr0 [ $first ][ $prefix ],
( array ) $paths
);
}
}
/**
* Registers a set of PSR - 4 directories for a given namespace , either
* appending or prepending to the ones previously set for this namespace .
*
* @ param string $prefix The prefix / namespace , with trailing '\\'
* @ param array | string $paths The PSR - 0 base directories
* @ param bool $prepend Whether to prepend the directories
*
* @ throws \InvalidArgumentException
*/
public function addPsr4 ( $prefix , $paths , $prepend = false )
{
if ( ! $prefix ) {
// Register directories for the root namespace.
if ( $prepend ) {
$this -> fallbackDirsPsr4 = array_merge (
( array ) $paths ,
$this -> fallbackDirsPsr4
);
} else {
$this -> fallbackDirsPsr4 = array_merge (
$this -> fallbackDirsPsr4 ,
( array ) $paths
);
}
} elseif ( ! isset ( $this -> prefixDirsPsr4 [ $prefix ])) {
// Register directories for a new namespace.
$length = strlen ( $prefix );
if ( '\\' !== $prefix [ $length - 1 ]) {
throw new \InvalidArgumentException ( " A non-empty PSR-4 prefix must end with a namespace separator. " );
}
$this -> prefixLengthsPsr4 [ $prefix [ 0 ]][ $prefix ] = $length ;
$this -> prefixDirsPsr4 [ $prefix ] = ( array ) $paths ;
} elseif ( $prepend ) {
// Prepend directories for an already registered namespace.
$this -> prefixDirsPsr4 [ $prefix ] = array_merge (
( array ) $paths ,
$this -> prefixDirsPsr4 [ $prefix ]
);
} else {
// Append directories for an already registered namespace.
$this -> prefixDirsPsr4 [ $prefix ] = array_merge (
$this -> prefixDirsPsr4 [ $prefix ],
( array ) $paths
);
}
}
/**
* Registers a set of PSR - 0 directories for a given prefix ,
* replacing any others previously set for this prefix .
*
* @ param string $prefix The prefix
* @ param array | string $paths The PSR - 0 base directories
*/
public function set ( $prefix , $paths )
{
if ( ! $prefix ) {
$this -> fallbackDirsPsr0 = ( array ) $paths ;
} else {
$this -> prefixesPsr0 [ $prefix [ 0 ]][ $prefix ] = ( array ) $paths ;
}
}
/**
* Registers a set of PSR - 4 directories for a given namespace ,
* replacing any others previously set for this namespace .
*
* @ param string $prefix The prefix / namespace , with trailing '\\'
* @ param array | string $paths The PSR - 4 base directories
*
* @ throws \InvalidArgumentException
*/
public function setPsr4 ( $prefix , $paths )
{
if ( ! $prefix ) {
$this -> fallbackDirsPsr4 = ( array ) $paths ;
} else {
$length = strlen ( $prefix );
if ( '\\' !== $prefix [ $length - 1 ]) {
throw new \InvalidArgumentException ( " A non-empty PSR-4 prefix must end with a namespace separator. " );
}
$this -> prefixLengthsPsr4 [ $prefix [ 0 ]][ $prefix ] = $length ;
$this -> prefixDirsPsr4 [ $prefix ] = ( array ) $paths ;
}
}
/**
* Turns on searching the include path for class files .
*
* @ param bool $useIncludePath
*/
public function setUseIncludePath ( $useIncludePath )
{
$this -> useIncludePath = $useIncludePath ;
}
/**
* Can be used to check if the autoloader uses the include path to check
* for classes .
*
* @ return bool
*/
public function getUseIncludePath ()
{
return $this -> useIncludePath ;
}
/**
* Turns off searching the prefix and fallback directories for classes
* that have not been registered with the class map .
*
* @ param bool $classMapAuthoritative
*/
public function setClassMapAuthoritative ( $classMapAuthoritative )
{
$this -> classMapAuthoritative = $classMapAuthoritative ;
}
/**
* Should class lookup fail if not found in the current class map ?
*
* @ return bool
*/
public function isClassMapAuthoritative ()
{
return $this -> classMapAuthoritative ;
}
/**
* Registers this instance as an autoloader .
*
* @ param bool $prepend Whether to prepend the autoloader or not
*/
public function register ( $prepend = false )
{
spl_autoload_register ( array ( $this , 'loadClass' ), true , $prepend );
}
/**
* Unregisters this instance as an autoloader .
*/
public function unregister ()
{
spl_autoload_unregister ( array ( $this , 'loadClass' ));
}
/**
* Loads the given class or interface .
*
* @ param string $class The name of the class
* @ return bool | null True if loaded , null otherwise
*/
public function loadClass ( $class )
{
if ( $file = $this -> findFile ( $class )) {
includeFile ( $file );
return true ;
}
}
/**
* Finds the path to the file where the class is defined .
*
* @ param string $class The name of the class
*
* @ return string | false The path if found , false otherwise
*/
public function findFile ( $class )
{
// work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731
if ( '\\' == $class [ 0 ]) {
$class = substr ( $class , 1 );
}
// class map lookup
if ( isset ( $this -> classMap [ $class ])) {
return $this -> classMap [ $class ];
}
if ( $this -> classMapAuthoritative ) {
return false ;
}
$file = $this -> findFileWithExtension ( $class , '.php' );
// Search for Hack files if we are running on HHVM
if ( $file === null && defined ( 'HHVM_VERSION' )) {
$file = $this -> findFileWithExtension ( $class , '.hh' );
}
if ( $file === null ) {
// Remember that this class does not exist.
return $this -> classMap [ $class ] = false ;
}
return $file ;
}
private function findFileWithExtension ( $class , $ext )
{
// PSR-4 lookup
$logicalPathPsr4 = strtr ( $class , '\\' , DIRECTORY_SEPARATOR ) . $ext ;
$first = $class [ 0 ];
if ( isset ( $this -> prefixLengthsPsr4 [ $first ])) {
foreach ( $this -> prefixLengthsPsr4 [ $first ] as $prefix => $length ) {
if ( 0 === strpos ( $class , $prefix )) {
foreach ( $this -> prefixDirsPsr4 [ $prefix ] as $dir ) {
2015-09-04 13:20:09 -07:00
if ( file_exists ( $file = $dir . DIRECTORY_SEPARATOR . substr ( $logicalPathPsr4 , $length ))) {
2015-08-17 17:00:26 -07:00
return $file ;
}
}
}
}
}
// PSR-4 fallback dirs
foreach ( $this -> fallbackDirsPsr4 as $dir ) {
2015-09-04 13:20:09 -07:00
if ( file_exists ( $file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4 )) {
2015-08-17 17:00:26 -07:00
return $file ;
}
}
// PSR-0 lookup
if ( false !== $pos = strrpos ( $class , '\\' )) {
// namespaced class name
$logicalPathPsr0 = substr ( $logicalPathPsr4 , 0 , $pos + 1 )
. strtr ( substr ( $logicalPathPsr4 , $pos + 1 ), '_' , DIRECTORY_SEPARATOR );
} else {
// PEAR-like class name
$logicalPathPsr0 = strtr ( $class , '_' , DIRECTORY_SEPARATOR ) . $ext ;
}
if ( isset ( $this -> prefixesPsr0 [ $first ])) {
foreach ( $this -> prefixesPsr0 [ $first ] as $prefix => $dirs ) {
if ( 0 === strpos ( $class , $prefix )) {
foreach ( $dirs as $dir ) {
2015-09-04 13:20:09 -07:00
if ( file_exists ( $file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0 )) {
2015-08-17 17:00:26 -07:00
return $file ;
}
}
}
}
}
// PSR-0 fallback dirs
foreach ( $this -> fallbackDirsPsr0 as $dir ) {
2015-09-04 13:20:09 -07:00
if ( file_exists ( $file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0 )) {
2015-08-17 17:00:26 -07:00
return $file ;
}
}
// PSR-0 include paths.
if ( $this -> useIncludePath && $file = stream_resolve_include_path ( $logicalPathPsr0 )) {
return $file ;
}
}
}
/**
* Scope isolated include .
*
* Prevents access to $this / self from included files .
*/
function includeFile ( $file )
{
include $file ;
}