File indexing completed on 2024-12-22 05:36:49
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 * PSR-0 compliant autoloader 0026 * 0027 * Allows autoloading both namespaced and vendor-prefixed classes. Class 0028 * lookups are performed on the filesystem. If a class file for the referenced 0029 * class is not found, a PHP warning will be raised by include(). 0030 * 0031 * @package Zend_Loader 0032 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0033 * @license New BSD {@link http://framework.zend.com/license/new-bsd} 0034 */ 0035 class Zend_Loader_StandardAutoloader implements Zend_Loader_SplAutoloader 0036 { 0037 const NS_SEPARATOR = '\\'; 0038 const PREFIX_SEPARATOR = '_'; 0039 const LOAD_NS = 'namespaces'; 0040 const LOAD_PREFIX = 'prefixes'; 0041 const ACT_AS_FALLBACK = 'fallback_autoloader'; 0042 const AUTOREGISTER_ZF = 'autoregister_zf'; 0043 0044 /** 0045 * @var array Namespace/directory pairs to search; ZF library added by default 0046 */ 0047 protected $namespaces = array(); 0048 0049 /** 0050 * @var array Prefix/directory pairs to search 0051 */ 0052 protected $prefixes = array(); 0053 0054 /** 0055 * @var bool Whether or not the autoloader should also act as a fallback autoloader 0056 */ 0057 protected $fallbackAutoloaderFlag = false; 0058 0059 /** 0060 * @var bool 0061 */ 0062 protected $error; 0063 0064 /** 0065 * Constructor 0066 * 0067 * @param null|array|Traversable $options 0068 * @return void 0069 */ 0070 public function __construct($options = null) 0071 { 0072 if (null !== $options) { 0073 $this->setOptions($options); 0074 } 0075 } 0076 0077 /** 0078 * Configure autoloader 0079 * 0080 * Allows specifying both "namespace" and "prefix" pairs, using the 0081 * following structure: 0082 * <code> 0083 * array( 0084 * 'namespaces' => array( 0085 * 'Zend' => '/path/to/Zend/library', 0086 * 'Doctrine' => '/path/to/Doctrine/library', 0087 * ), 0088 * 'prefixes' => array( 0089 * 'Phly_' => '/path/to/Phly/library', 0090 * ), 0091 * 'fallback_autoloader' => true, 0092 * ) 0093 * </code> 0094 * 0095 * @param array|Traversable $options 0096 * @return Zend_Loader_StandardAutoloader 0097 */ 0098 public function setOptions($options) 0099 { 0100 if (!is_array($options) && !($options instanceof Traversable)) { 0101 // require_once dirname(__FILE__) . '/Exception/InvalidArgumentException.php'; 0102 throw new Zend_Loader_Exception_InvalidArgumentException('Options must be either an array or Traversable'); 0103 } 0104 0105 foreach ($options as $type => $pairs) { 0106 switch ($type) { 0107 case self::AUTOREGISTER_ZF: 0108 if ($pairs) { 0109 $this->registerPrefix('Zend', dirname(dirname(__FILE__))); 0110 } 0111 break; 0112 case self::LOAD_NS: 0113 if (is_array($pairs) || $pairs instanceof Traversable) { 0114 $this->registerNamespaces($pairs); 0115 } 0116 break; 0117 case self::LOAD_PREFIX: 0118 if (is_array($pairs) || $pairs instanceof Traversable) { 0119 $this->registerPrefixes($pairs); 0120 } 0121 break; 0122 case self::ACT_AS_FALLBACK: 0123 $this->setFallbackAutoloader($pairs); 0124 break; 0125 default: 0126 // ignore 0127 } 0128 } 0129 return $this; 0130 } 0131 0132 /** 0133 * Set flag indicating fallback autoloader status 0134 * 0135 * @param bool $flag 0136 * @return Zend_Loader_StandardAutoloader 0137 */ 0138 public function setFallbackAutoloader($flag) 0139 { 0140 $this->fallbackAutoloaderFlag = (bool) $flag; 0141 return $this; 0142 } 0143 0144 /** 0145 * Is this autoloader acting as a fallback autoloader? 0146 * 0147 * @return bool 0148 */ 0149 public function isFallbackAutoloader() 0150 { 0151 return $this->fallbackAutoloaderFlag; 0152 } 0153 0154 /** 0155 * Register a namespace/directory pair 0156 * 0157 * @param string $namespace 0158 * @param string $directory 0159 * @return Zend_Loader_StandardAutoloader 0160 */ 0161 public function registerNamespace($namespace, $directory) 0162 { 0163 $namespace = rtrim($namespace, self::NS_SEPARATOR). self::NS_SEPARATOR; 0164 $this->namespaces[$namespace] = $this->normalizeDirectory($directory); 0165 return $this; 0166 } 0167 0168 /** 0169 * Register many namespace/directory pairs at once 0170 * 0171 * @param array $namespaces 0172 * @return Zend_Loader_StandardAutoloader 0173 */ 0174 public function registerNamespaces($namespaces) 0175 { 0176 if (!is_array($namespaces) && !$namespaces instanceof Traversable) { 0177 // require_once dirname(__FILE__) . '/Exception/InvalidArgumentException.php'; 0178 throw new Zend_Loader_Exception_InvalidArgumentException('Namespace pairs must be either an array or Traversable'); 0179 } 0180 0181 foreach ($namespaces as $namespace => $directory) { 0182 $this->registerNamespace($namespace, $directory); 0183 } 0184 return $this; 0185 } 0186 0187 /** 0188 * Register a prefix/directory pair 0189 * 0190 * @param string $prefix 0191 * @param string $directory 0192 * @return Zend_Loader_StandardAutoloader 0193 */ 0194 public function registerPrefix($prefix, $directory) 0195 { 0196 $prefix = rtrim($prefix, self::PREFIX_SEPARATOR). self::PREFIX_SEPARATOR; 0197 $this->prefixes[$prefix] = $this->normalizeDirectory($directory); 0198 return $this; 0199 } 0200 0201 /** 0202 * Register many namespace/directory pairs at once 0203 * 0204 * @param array $prefixes 0205 * @return Zend_Loader_StandardAutoloader 0206 */ 0207 public function registerPrefixes($prefixes) 0208 { 0209 if (!is_array($prefixes) && !$prefixes instanceof Traversable) { 0210 // require_once dirname(__FILE__) . '/Exception/InvalidArgumentException.php'; 0211 throw new Zend_Loader_Exception_InvalidArgumentException('Prefix pairs must be either an array or Traversable'); 0212 } 0213 0214 foreach ($prefixes as $prefix => $directory) { 0215 $this->registerPrefix($prefix, $directory); 0216 } 0217 return $this; 0218 } 0219 0220 /** 0221 * Defined by Autoloadable; autoload a class 0222 * 0223 * @param string $class 0224 * @return false|string 0225 */ 0226 public function autoload($class) 0227 { 0228 $isFallback = $this->isFallbackAutoloader(); 0229 if (false !== strpos($class, self::NS_SEPARATOR)) { 0230 if ($this->loadClass($class, self::LOAD_NS)) { 0231 return $class; 0232 } elseif ($isFallback) { 0233 return $this->loadClass($class, self::ACT_AS_FALLBACK); 0234 } 0235 return false; 0236 } 0237 if (false !== strpos($class, self::PREFIX_SEPARATOR)) { 0238 if ($this->loadClass($class, self::LOAD_PREFIX)) { 0239 return $class; 0240 } elseif ($isFallback) { 0241 return $this->loadClass($class, self::ACT_AS_FALLBACK); 0242 } 0243 return false; 0244 } 0245 if ($isFallback) { 0246 return $this->loadClass($class, self::ACT_AS_FALLBACK); 0247 } 0248 return false; 0249 } 0250 0251 /** 0252 * Register the autoloader with spl_autoload 0253 * 0254 * @return void 0255 */ 0256 public function register() 0257 { 0258 spl_autoload_register(array($this, 'autoload')); 0259 } 0260 0261 /** 0262 * Error handler 0263 * 0264 * Used by {@link loadClass} during fallback autoloading in PHP versions 0265 * prior to 5.3.0. 0266 * 0267 * @param mixed $errno 0268 * @param mixed $errstr 0269 * @return void 0270 */ 0271 public function handleError($errno, $errstr) 0272 { 0273 $this->error = true; 0274 } 0275 0276 /** 0277 * Transform the class name to a filename 0278 * 0279 * @param string $class 0280 * @param string $directory 0281 * @return string 0282 */ 0283 protected function transformClassNameToFilename($class, $directory) 0284 { 0285 // $class may contain a namespace portion, in which case we need 0286 // to preserve any underscores in that portion. 0287 $matches = array(); 0288 preg_match('/(?P<namespace>.+\\\)?(?P<class>[^\\\]+$)/', $class, $matches); 0289 0290 $class = (isset($matches['class'])) ? $matches['class'] : ''; 0291 $namespace = (isset($matches['namespace'])) ? $matches['namespace'] : ''; 0292 0293 return $directory 0294 . str_replace(self::NS_SEPARATOR, '/', $namespace) 0295 . str_replace(self::PREFIX_SEPARATOR, '/', $class) 0296 . '.php'; 0297 } 0298 0299 /** 0300 * Load a class, based on its type (namespaced or prefixed) 0301 * 0302 * @param string $class 0303 * @param string $type 0304 * @return void 0305 */ 0306 protected function loadClass($class, $type) 0307 { 0308 if (!in_array($type, array(self::LOAD_NS, self::LOAD_PREFIX, self::ACT_AS_FALLBACK))) { 0309 // require_once dirname(__FILE__) . '/Exception/InvalidArgumentException.php'; 0310 throw new Zend_Loader_Exception_InvalidArgumentException(); 0311 } 0312 0313 // Fallback autoloading 0314 if ($type === self::ACT_AS_FALLBACK) { 0315 // create filename 0316 $filename = $this->transformClassNameToFilename($class, ''); 0317 if (version_compare(PHP_VERSION, '5.3.2', '>=')) { 0318 $resolvedName = stream_resolve_include_path($filename); 0319 if ($resolvedName !== false) { 0320 return include $resolvedName; 0321 } 0322 return false; 0323 } 0324 $this->error = false; 0325 set_error_handler(array($this, 'handleError'), E_WARNING); 0326 include $filename; 0327 restore_error_handler(); 0328 if ($this->error) { 0329 return false; 0330 } 0331 return class_exists($class, false); 0332 } 0333 0334 // Namespace and/or prefix autoloading 0335 foreach ($this->$type as $leader => $path) { 0336 if (0 === strpos($class, $leader)) { 0337 // Trim off leader (namespace or prefix) 0338 $trimmedClass = substr($class, strlen($leader)); 0339 0340 // create filename 0341 $filename = $this->transformClassNameToFilename($trimmedClass, $path); 0342 if (file_exists($filename)) { 0343 return include $filename; 0344 } 0345 return false; 0346 } 0347 } 0348 return false; 0349 } 0350 0351 /** 0352 * Normalize the directory to include a trailing directory separator 0353 * 0354 * @param string $directory 0355 * @return string 0356 */ 0357 protected function normalizeDirectory($directory) 0358 { 0359 $last = $directory[strlen($directory) - 1]; 0360 if (in_array($last, array('/', '\\'))) { 0361 $directory[strlen($directory) - 1] = DIRECTORY_SEPARATOR; 0362 return $directory; 0363 } 0364 $directory .= DIRECTORY_SEPARATOR; 0365 return $directory; 0366 } 0367 0368 }