File indexing completed on 2024-05-12 06:02:43

0001 <?php
0002 /**
0003  * Zend Framework
0004  *
0005  * LICENSE
0006  *
0007  * This source file is subject to the new BSD license that is bundled
0008  * with this package in the file LICENSE.txt.
0009  * It is also available through the world-wide-web at this URL:
0010  * http://framework.zend.com/license/new-bsd
0011  * If you did not receive a copy of the license and are unable to
0012  * obtain it through the world-wide-web, please send an email
0013  * to license@zend.com so we can send you a copy immediately.
0014  *
0015  * @category   Zend
0016  * @package    Zend_Loader
0017  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0018  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0019  */
0020 
0021 // Grab SplAutoloader interface
0022 // require_once dirname(__FILE__) . '/SplAutoloader.php';
0023 
0024 /**
0025  * Class-map autoloader
0026  *
0027  * Utilizes class-map files to lookup classfile locations.
0028  * 
0029  * @package    Zend_Loader
0030  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0031  * @license    New BSD {@link http://framework.zend.com/license/new-bsd}
0032  */
0033 class Zend_Loader_ClassMapAutoloader implements Zend_Loader_SplAutoloader
0034 {
0035     /**
0036      * Registry of map files that have already been loaded
0037      * @var array
0038      */
0039     protected $mapsLoaded = array();
0040 
0041     /**
0042      * Class name/filename map
0043      * @var array
0044      */
0045     protected $map = array();
0046 
0047     /**
0048      * Constructor
0049      *
0050      * Create a new instance, and optionally configure the autoloader.
0051      * 
0052      * @param  null|array|Traversable $options 
0053      * @return void
0054      */
0055     public function __construct($options = null)
0056     {
0057         if (null !== $options) {
0058             $this->setOptions($options);
0059         }
0060     }
0061 
0062     /**
0063      * Configure the autoloader
0064      *
0065      * Proxies to {@link registerAutoloadMaps()}.
0066      * 
0067      * @param  array|Traversable $options 
0068      * @return Zend_Loader_ClassMapAutoloader
0069      */
0070     public function setOptions($options)
0071     {
0072         $this->registerAutoloadMaps($options);
0073         return $this;
0074     }
0075 
0076     /**
0077      * Register an autoload map
0078      *
0079      * An autoload map may be either an associative array, or a file returning
0080      * an associative array.
0081      *
0082      * An autoload map should be an associative array containing 
0083      * classname/file pairs.
0084      * 
0085      * @param  string|array $location 
0086      * @return Zend_Loader_ClassMapAutoloader
0087      */
0088     public function registerAutoloadMap($map)
0089     {
0090         if (is_string($map)) {
0091             $location = $map;
0092             if ($this === ($map = $this->loadMapFromFile($location))) {
0093                 return $this;
0094             }
0095         }
0096 
0097         if (!is_array($map)) {
0098             // require_once dirname(__FILE__) . '/Exception/InvalidArgumentException.php';
0099             throw new Zend_Loader_Exception_InvalidArgumentException('Map file provided does not return a map');
0100         }
0101 
0102         $this->map = array_merge($this->map, $map);
0103 
0104         if (isset($location)) {
0105             $this->mapsLoaded[] = $location;
0106         }
0107 
0108         return $this;
0109     }
0110 
0111     /**
0112      * Register many autoload maps at once
0113      * 
0114      * @param  array $locations 
0115      * @return Zend_Loader_ClassMapAutoloader
0116      */
0117     public function registerAutoloadMaps($locations)
0118     {
0119         if (!is_array($locations) && !($locations instanceof Traversable)) {
0120             // require_once dirname(__FILE__) . '/Exception/InvalidArgumentException.php';
0121             throw new Zend_Loader_Exception_InvalidArgumentException('Map list must be an array or implement Traversable');
0122         }
0123         foreach ($locations as $location) {
0124             $this->registerAutoloadMap($location);
0125         }
0126         return $this;
0127     }
0128 
0129     /**
0130      * Retrieve current autoload map
0131      * 
0132      * @return array
0133      */
0134     public function getAutoloadMap()
0135     {
0136         return $this->map;
0137     }
0138 
0139     /**
0140      * Defined by Autoloadable
0141      * 
0142      * @param  string $class 
0143      * @return void
0144      */
0145     public function autoload($class)
0146     {
0147         if (isset($this->map[$class])) {
0148             // require_once $this->map[$class];
0149         }
0150     }
0151 
0152     /**
0153      * Register the autoloader with spl_autoload registry
0154      * 
0155      * @return void
0156      */
0157     public function register()
0158     {
0159         if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
0160             spl_autoload_register(array($this, 'autoload'), true, true);
0161         } else {
0162             spl_autoload_register(array($this, 'autoload'), true);
0163         }
0164     }
0165 
0166     /**
0167      * Load a map from a file
0168      *
0169      * If the map has been previously loaded, returns the current instance;
0170      * otherwise, returns whatever was returned by calling include() on the
0171      * location.
0172      * 
0173      * @param  string $location 
0174      * @return Zend_Loader_ClassMapAutoloader|mixed
0175      * @throws Zend_Loader_Exception_InvalidArgumentException for nonexistent locations
0176      */
0177     protected function loadMapFromFile($location)
0178     {
0179         if (!file_exists($location)) {
0180             // require_once dirname(__FILE__) . '/Exception/InvalidArgumentException.php';
0181             throw new Zend_Loader_Exception_InvalidArgumentException('Map file provided does not exist');
0182         }
0183 
0184         if (!$path = self::realPharPath($location)) {
0185             $path = realpath($location);
0186         }
0187 
0188         if (in_array($path, $this->mapsLoaded)) {
0189             // Already loaded this map
0190             return $this;
0191         }
0192 
0193         $map = include $path;
0194 
0195         return $map;
0196     }
0197 
0198     /**
0199      * Resolve the real_path() to a file within a phar.
0200      *
0201      * @see    https://bugs.php.net/bug.php?id=52769 
0202      * @param  string $path 
0203      * @return string
0204      */
0205     public static function realPharPath($path)
0206     {
0207         if (strpos($path, 'phar:///') !== 0) {
0208             return;
0209         }
0210         
0211         $parts = explode('/', str_replace(array('/','\\'), '/', substr($path, 8)));
0212         $parts = array_values(array_filter($parts, array(__CLASS__, 'concatPharParts')));
0213 
0214         array_walk($parts, array(__CLASS__, 'resolvePharParentPath'), $parts);
0215 
0216         if (file_exists($realPath = 'phar:///' . implode('/', $parts))) {
0217             return $realPath;
0218         }
0219     }
0220 
0221     /**
0222      * Helper callback for filtering phar paths
0223      * 
0224      * @param  string $part 
0225      * @return bool
0226      */
0227     public static function concatPharParts($part)
0228     {
0229         return ($part !== '' && $part !== '.');
0230     }
0231 
0232     /**
0233      * Helper callback to resolve a parent path in a Phar archive
0234      * 
0235      * @param  string $value 
0236      * @param  int $key 
0237      * @param  array $parts 
0238      * @return void
0239      */
0240     public static function resolvePharParentPath($value, $key, &$parts)
0241     {
0242         if ($value !== '...') {
0243             return;
0244         }
0245         unset($parts[$key], $parts[$key-1]);
0246         $parts = array_values($parts);
0247     }
0248 }