web/lib/Zend/Loader/ClassMapAutoloader.php
changeset 886 1e110b03ae96
parent 808 6b6c2214f778
child 1230 68c69c656a2c
equal deleted inserted replaced
885:2251fb41dbc7 886:1e110b03ae96
       
     1 <?php
       
     2 /**
       
     3  * Zend Framework
       
     4  *
       
     5  * LICENSE
       
     6  *
       
     7  * This source file is subject to the new BSD license that is bundled
       
     8  * with this package in the file LICENSE.txt.
       
     9  * It is also available through the world-wide-web at this URL:
       
    10  * http://framework.zend.com/license/new-bsd
       
    11  * If you did not receive a copy of the license and are unable to
       
    12  * obtain it through the world-wide-web, please send an email
       
    13  * to license@zend.com so we can send you a copy immediately.
       
    14  *
       
    15  * @category   Zend
       
    16  * @package    Zend_Loader
       
    17  * @copyright  Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
       
    18  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    19  */
       
    20 
       
    21 // Grab SplAutoloader interface
       
    22 require_once dirname(__FILE__) . '/SplAutoloader.php';
       
    23 
       
    24 /**
       
    25  * Class-map autoloader
       
    26  *
       
    27  * Utilizes class-map files to lookup classfile locations.
       
    28  * 
       
    29  * @package    Zend_Loader
       
    30  * @copyright  Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
       
    31  * @license    New BSD {@link http://framework.zend.com/license/new-bsd}
       
    32  */
       
    33 class Zend_Loader_ClassMapAutoloader implements Zend_Loader_SplAutoloader
       
    34 {
       
    35     /**
       
    36      * Registry of map files that have already been loaded
       
    37      * @var array
       
    38      */
       
    39     protected $mapsLoaded = array();
       
    40 
       
    41     /**
       
    42      * Class name/filename map
       
    43      * @var array
       
    44      */
       
    45     protected $map = array();
       
    46 
       
    47     /**
       
    48      * Constructor
       
    49      *
       
    50      * Create a new instance, and optionally configure the autoloader.
       
    51      * 
       
    52      * @param  null|array|Traversable $options 
       
    53      * @return void
       
    54      */
       
    55     public function __construct($options = null)
       
    56     {
       
    57         if (null !== $options) {
       
    58             $this->setOptions($options);
       
    59         }
       
    60     }
       
    61 
       
    62     /**
       
    63      * Configure the autoloader
       
    64      *
       
    65      * Proxies to {@link registerAutoloadMaps()}.
       
    66      * 
       
    67      * @param  array|Traversable $options 
       
    68      * @return Zend_Loader_ClassMapAutoloader
       
    69      */
       
    70     public function setOptions($options)
       
    71     {
       
    72         $this->registerAutoloadMaps($options);
       
    73         return $this;
       
    74     }
       
    75 
       
    76     /**
       
    77      * Register an autoload map
       
    78      *
       
    79      * An autoload map may be either an associative array, or a file returning
       
    80      * an associative array.
       
    81      *
       
    82      * An autoload map should be an associative array containing 
       
    83      * classname/file pairs.
       
    84      * 
       
    85      * @param  string|array $location 
       
    86      * @return Zend_Loader_ClassMapAutoloader
       
    87      */
       
    88     public function registerAutoloadMap($map)
       
    89     {
       
    90         if (is_string($map)) {
       
    91             $location = $map;
       
    92             if ($this === ($map = $this->loadMapFromFile($location))) {
       
    93                 return $this;
       
    94             }
       
    95         }
       
    96 
       
    97         if (!is_array($map)) {
       
    98             require_once dirname(__FILE__) . '/Exception/InvalidArgumentException.php';
       
    99             throw new Zend_Loader_Exception_InvalidArgumentException('Map file provided does not return a map');
       
   100         }
       
   101 
       
   102         $this->map = array_merge($this->map, $map);
       
   103 
       
   104         if (isset($location)) {
       
   105             $this->mapsLoaded[] = $location;
       
   106         }
       
   107 
       
   108         return $this;
       
   109     }
       
   110 
       
   111     /**
       
   112      * Register many autoload maps at once
       
   113      * 
       
   114      * @param  array $locations 
       
   115      * @return Zend_Loader_ClassMapAutoloader
       
   116      */
       
   117     public function registerAutoloadMaps($locations)
       
   118     {
       
   119         if (!is_array($locations) && !($locations instanceof Traversable)) {
       
   120             require_once dirname(__FILE__) . '/Exception/InvalidArgumentException.php';
       
   121             throw new Zend_Loader_Exception_InvalidArgumentException('Map list must be an array or implement Traversable');
       
   122         }
       
   123         foreach ($locations as $location) {
       
   124             $this->registerAutoloadMap($location);
       
   125         }
       
   126         return $this;
       
   127     }
       
   128 
       
   129     /**
       
   130      * Retrieve current autoload map
       
   131      * 
       
   132      * @return array
       
   133      */
       
   134     public function getAutoloadMap()
       
   135     {
       
   136         return $this->map;
       
   137     }
       
   138 
       
   139     /**
       
   140      * Defined by Autoloadable
       
   141      * 
       
   142      * @param  string $class 
       
   143      * @return void
       
   144      */
       
   145     public function autoload($class)
       
   146     {
       
   147         if (isset($this->map[$class])) {
       
   148             require_once $this->map[$class];
       
   149         }
       
   150     }
       
   151 
       
   152     /**
       
   153      * Register the autoloader with spl_autoload registry
       
   154      * 
       
   155      * @return void
       
   156      */
       
   157     public function register()
       
   158     {
       
   159         if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
       
   160             spl_autoload_register(array($this, 'autoload'), true, true);
       
   161         } else {
       
   162             spl_autoload_register(array($this, 'autoload'), true);
       
   163         }
       
   164     }
       
   165 
       
   166     /**
       
   167      * Load a map from a file
       
   168      *
       
   169      * If the map has been previously loaded, returns the current instance;
       
   170      * otherwise, returns whatever was returned by calling include() on the
       
   171      * location.
       
   172      * 
       
   173      * @param  string $location 
       
   174      * @return Zend_Loader_ClassMapAutoloader|mixed
       
   175      * @throws Zend_Loader_Exception_InvalidArgumentException for nonexistent locations
       
   176      */
       
   177     protected function loadMapFromFile($location)
       
   178     {
       
   179         if (!file_exists($location)) {
       
   180             require_once dirname(__FILE__) . '/Exception/InvalidArgumentException.php';
       
   181             throw new Zend_Loader_Exception_InvalidArgumentException('Map file provided does not exist');
       
   182         }
       
   183 
       
   184         if (!$path = self::realPharPath($location)) {
       
   185             $path = realpath($location);
       
   186         }
       
   187 
       
   188         if (in_array($path, $this->mapsLoaded)) {
       
   189             // Already loaded this map
       
   190             return $this;
       
   191         }
       
   192 
       
   193         $map = include $path;
       
   194 
       
   195         return $map;
       
   196     }
       
   197 
       
   198     /**
       
   199      * Resolve the real_path() to a file within a phar.
       
   200      *
       
   201      * @see    https://bugs.php.net/bug.php?id=52769 
       
   202      * @param  string $path 
       
   203      * @return string
       
   204      */
       
   205     public static function realPharPath($path)
       
   206     {
       
   207         if (strpos($path, 'phar:///') !== 0) {
       
   208             return;
       
   209         }
       
   210         
       
   211         $parts = explode('/', str_replace(array('/','\\'), '/', substr($path, 8)));
       
   212         $parts = array_values(array_filter($parts, array(__CLASS__, 'concatPharParts')));
       
   213 
       
   214         array_walk($parts, array(__CLASS__, 'resolvePharParentPath'), $parts);
       
   215 
       
   216         if (file_exists($realPath = 'phar:///' . implode('/', $parts))) {
       
   217             return $realPath;
       
   218         }
       
   219     }
       
   220 
       
   221     /**
       
   222      * Helper callback for filtering phar paths
       
   223      * 
       
   224      * @param  string $part 
       
   225      * @return bool
       
   226      */
       
   227     public static function concatPharParts($part)
       
   228     {
       
   229         return ($part !== '' && $part !== '.');
       
   230     }
       
   231 
       
   232     /**
       
   233      * Helper callback to resolve a parent path in a Phar archive
       
   234      * 
       
   235      * @param  string $value 
       
   236      * @param  int $key 
       
   237      * @param  array $parts 
       
   238      * @return void
       
   239      */
       
   240     public static function resolvePharParentPath($value, $key, &$parts)
       
   241     {
       
   242         if ($value !== '...') {
       
   243             return;
       
   244         }
       
   245         unset($parts[$key], $parts[$key-1]);
       
   246         $parts = array_values($parts);
       
   247     }
       
   248 }