vendor/symfony/src/Symfony/Component/ClassLoader/UniversalClassLoader.php
changeset 0 7f95f8617b0b
equal deleted inserted replaced
-1:000000000000 0:7f95f8617b0b
       
     1 <?php
       
     2 
       
     3 /*
       
     4  * This file is part of the Symfony package.
       
     5  *
       
     6  * (c) Fabien Potencier <fabien@symfony.com>
       
     7  *
       
     8  * For the full copyright and license information, please view the LICENSE
       
     9  * file that was distributed with this source code.
       
    10  */
       
    11 
       
    12 namespace Symfony\Component\ClassLoader;
       
    13 
       
    14 /**
       
    15  * UniversalClassLoader implements a "universal" autoloader for PHP 5.3.
       
    16  *
       
    17  * It is able to load classes that use either:
       
    18  *
       
    19  *  * The technical interoperability standards for PHP 5.3 namespaces and
       
    20  *    class names (http://groups.google.com/group/php-standards/web/psr-0-final-proposal);
       
    21  *
       
    22  *  * The PEAR naming convention for classes (http://pear.php.net/).
       
    23  *
       
    24  * Classes from a sub-namespace or a sub-hierarchy of PEAR classes can be
       
    25  * looked for in a list of locations to ease the vendoring of a sub-set of
       
    26  * classes for large projects.
       
    27  *
       
    28  * Example usage:
       
    29  *
       
    30  *     $loader = new UniversalClassLoader();
       
    31  *
       
    32  *     // register classes with namespaces
       
    33  *     $loader->registerNamespaces(array(
       
    34  *         'Symfony\Component' => __DIR__.'/component',
       
    35  *         'Symfony'           => __DIR__.'/framework',
       
    36  *         'Sensio'            => array(__DIR__.'/src', __DIR__.'/vendor'),
       
    37  *     ));
       
    38  *
       
    39  *     // register a library using the PEAR naming convention
       
    40  *     $loader->registerPrefixes(array(
       
    41  *         'Swift_' => __DIR__.'/Swift',
       
    42  *     ));
       
    43  *
       
    44  *     // activate the autoloader
       
    45  *     $loader->register();
       
    46  *
       
    47  * In this example, if you try to use a class in the Symfony\Component
       
    48  * namespace or one of its children (Symfony\Component\Console for instance),
       
    49  * the autoloader will first look for the class under the component/
       
    50  * directory, and it will then fallback to the framework/ directory if not
       
    51  * found before giving up.
       
    52  *
       
    53  * @author Fabien Potencier <fabien@symfony.com>
       
    54  *
       
    55  * @api
       
    56  */
       
    57 class UniversalClassLoader
       
    58 {
       
    59     private $namespaces = array();
       
    60     private $prefixes = array();
       
    61     private $namespaceFallbacks = array();
       
    62     private $prefixFallbacks = array();
       
    63 
       
    64     /**
       
    65      * Gets the configured namespaces.
       
    66      *
       
    67      * @return array A hash with namespaces as keys and directories as values
       
    68      */
       
    69     public function getNamespaces()
       
    70     {
       
    71         return $this->namespaces;
       
    72     }
       
    73 
       
    74     /**
       
    75      * Gets the configured class prefixes.
       
    76      *
       
    77      * @return array A hash with class prefixes as keys and directories as values
       
    78      */
       
    79     public function getPrefixes()
       
    80     {
       
    81         return $this->prefixes;
       
    82     }
       
    83 
       
    84     /**
       
    85      * Gets the directory(ies) to use as a fallback for namespaces.
       
    86      *
       
    87      * @return array An array of directories
       
    88      */
       
    89     public function getNamespaceFallbacks()
       
    90     {
       
    91         return $this->namespaceFallbacks;
       
    92     }
       
    93 
       
    94     /**
       
    95      * Gets the directory(ies) to use as a fallback for class prefixes.
       
    96      *
       
    97      * @return array An array of directories
       
    98      */
       
    99     public function getPrefixFallbacks()
       
   100     {
       
   101         return $this->prefixFallbacks;
       
   102     }
       
   103 
       
   104     /**
       
   105      * Registers the directory to use as a fallback for namespaces.
       
   106      *
       
   107      * @param array $dirs An array of directories
       
   108      *
       
   109      * @api
       
   110      */
       
   111     public function registerNamespaceFallbacks(array $dirs)
       
   112     {
       
   113         $this->namespaceFallbacks = $dirs;
       
   114     }
       
   115 
       
   116     /**
       
   117      * Registers the directory to use as a fallback for class prefixes.
       
   118      *
       
   119      * @param array $dirs An array of directories
       
   120      *
       
   121      * @api
       
   122      */
       
   123     public function registerPrefixFallbacks(array $dirs)
       
   124     {
       
   125         $this->prefixFallbacks = $dirs;
       
   126     }
       
   127 
       
   128     /**
       
   129      * Registers an array of namespaces
       
   130      *
       
   131      * @param array $namespaces An array of namespaces (namespaces as keys and locations as values)
       
   132      *
       
   133      * @api
       
   134      */
       
   135     public function registerNamespaces(array $namespaces)
       
   136     {
       
   137         foreach ($namespaces as $namespace => $locations) {
       
   138             $this->namespaces[$namespace] = (array) $locations;
       
   139         }
       
   140     }
       
   141 
       
   142     /**
       
   143      * Registers a namespace.
       
   144      *
       
   145      * @param string       $namespace The namespace
       
   146      * @param array|string $paths     The location(s) of the namespace
       
   147      *
       
   148      * @api
       
   149      */
       
   150     public function registerNamespace($namespace, $paths)
       
   151     {
       
   152         $this->namespaces[$namespace] = (array) $paths;
       
   153     }
       
   154 
       
   155     /**
       
   156      * Registers an array of classes using the PEAR naming convention.
       
   157      *
       
   158      * @param array $classes An array of classes (prefixes as keys and locations as values)
       
   159      *
       
   160      * @api
       
   161      */
       
   162     public function registerPrefixes(array $classes)
       
   163     {
       
   164         foreach ($classes as $prefix => $locations) {
       
   165             $this->prefixes[$prefix] = (array) $locations;
       
   166         }
       
   167     }
       
   168 
       
   169     /**
       
   170      * Registers a set of classes using the PEAR naming convention.
       
   171      *
       
   172      * @param string       $prefix  The classes prefix
       
   173      * @param array|string $paths   The location(s) of the classes
       
   174      *
       
   175      * @api
       
   176      */
       
   177     public function registerPrefix($prefix, $paths)
       
   178     {
       
   179         $this->prefixes[$prefix] = (array) $paths;
       
   180     }
       
   181 
       
   182     /**
       
   183      * Registers this instance as an autoloader.
       
   184      *
       
   185      * @param Boolean $prepend Whether to prepend the autoloader or not
       
   186      *
       
   187      * @api
       
   188      */
       
   189     public function register($prepend = false)
       
   190     {
       
   191         spl_autoload_register(array($this, 'loadClass'), true, $prepend);
       
   192     }
       
   193 
       
   194     /**
       
   195      * Loads the given class or interface.
       
   196      *
       
   197      * @param string $class The name of the class
       
   198      */
       
   199     public function loadClass($class)
       
   200     {
       
   201         if ($file = $this->findFile($class)) {
       
   202             require $file;
       
   203         }
       
   204     }
       
   205 
       
   206     /**
       
   207      * Finds the path to the file where the class is defined.
       
   208      *
       
   209      * @param string $class The name of the class
       
   210      *
       
   211      * @return string|null The path, if found
       
   212      */
       
   213     public function findFile($class)
       
   214     {
       
   215         if ('\\' == $class[0]) {
       
   216             $class = substr($class, 1);
       
   217         }
       
   218 
       
   219         if (false !== $pos = strrpos($class, '\\')) {
       
   220             // namespaced class name
       
   221             $namespace = substr($class, 0, $pos);
       
   222             foreach ($this->namespaces as $ns => $dirs) {
       
   223                 if (0 !== strpos($namespace, $ns)) {
       
   224                     continue;
       
   225                 }
       
   226 
       
   227                 foreach ($dirs as $dir) {
       
   228                     $className = substr($class, $pos + 1);
       
   229                     $file = $dir.DIRECTORY_SEPARATOR.str_replace('\\', DIRECTORY_SEPARATOR, $namespace).DIRECTORY_SEPARATOR.str_replace('_', DIRECTORY_SEPARATOR, $className).'.php';
       
   230                     if (file_exists($file)) {
       
   231                         return $file;
       
   232                     }
       
   233                 }
       
   234             }
       
   235 
       
   236             foreach ($this->namespaceFallbacks as $dir) {
       
   237                 $file = $dir.DIRECTORY_SEPARATOR.str_replace('\\', DIRECTORY_SEPARATOR, $class).'.php';
       
   238                 if (file_exists($file)) {
       
   239                     return $file;
       
   240                 }
       
   241             }
       
   242         } else {
       
   243             // PEAR-like class name
       
   244             foreach ($this->prefixes as $prefix => $dirs) {
       
   245                 if (0 !== strpos($class, $prefix)) {
       
   246                     continue;
       
   247                 }
       
   248 
       
   249                 foreach ($dirs as $dir) {
       
   250                     $file = $dir.DIRECTORY_SEPARATOR.str_replace('_', DIRECTORY_SEPARATOR, $class).'.php';
       
   251                     if (file_exists($file)) {
       
   252                         return $file;
       
   253                     }
       
   254                 }
       
   255             }
       
   256 
       
   257             foreach ($this->prefixFallbacks as $dir) {
       
   258                 $file = $dir.DIRECTORY_SEPARATOR.str_replace('_', DIRECTORY_SEPARATOR, $class).'.php';
       
   259                 if (file_exists($file)) {
       
   260                     return $file;
       
   261                 }
       
   262             }
       
   263         }
       
   264     }
       
   265 }