0,0 → 1,63 |
<?php |
/** |
* Zend Framework (http://framework.zend.com/) |
* |
* @link http://github.com/zendframework/zf2 for the canonical source repository |
* @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) |
* @license http://framework.zend.com/license/new-bsd New BSD License |
*/ |
|
namespace Zend\Loader; |
|
use Traversable; |
|
if (interface_exists('Zend\Loader\SplAutoloader')) return; |
|
/** |
* Defines an interface for classes that may register with the spl_autoload |
* registry |
*/ |
interface SplAutoloader |
{ |
/** |
* Constructor |
* |
* Allow configuration of the autoloader via the constructor. |
* |
* @param null|array|Traversable $options |
*/ |
public function __construct($options = null); |
|
/** |
* Configure the autoloader |
* |
* In most cases, $options should be either an associative array or |
* Traversable object. |
* |
* @param array|Traversable $options |
* @return SplAutoloader |
*/ |
public function setOptions($options); |
|
/** |
* Autoload a class |
* |
* @param $class |
* @return mixed |
* False [if unable to load $class] |
* get_class($class) [if $class is successfully loaded] |
*/ |
public function autoload($class); |
|
/** |
* Register the autoloader with spl_autoload registry |
* |
* Typically, the body of this will simply be: |
* <code> |
* spl_autoload_register(array($this, 'autoload')); |
* </code> |
* |
* @return void |
*/ |
public function register(); |
} |
Property changes: |
Added: svn:executable |
## -0,0 +1 ## |
+* |
\ No newline at end of property |
Index: Loader/StandardAutoloader.php |
=================================================================== |
--- Loader/StandardAutoloader.php (nonexistent) |
+++ Loader/StandardAutoloader.php (revision 79) |
@@ -0,0 +1,327 @@ |
+<?php |
+/** |
+ * Zend Framework (http://framework.zend.com/) |
+ * |
+ * @link http://github.com/zendframework/zf2 for the canonical source repository |
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) |
+ * @license http://framework.zend.com/license/new-bsd New BSD License |
+ */ |
+ |
+namespace Zend\Loader; |
+ |
+// Grab SplAutoloader interface |
+require_once __DIR__ . '/SplAutoloader.php'; |
+ |
+/** |
+ * PSR-0 compliant autoloader |
+ * |
+ * Allows autoloading both namespaced and vendor-prefixed classes. Class |
+ * lookups are performed on the filesystem. If a class file for the referenced |
+ * class is not found, a PHP warning will be raised by include(). |
+ */ |
+class StandardAutoloader implements SplAutoloader |
+{ |
+ const NS_SEPARATOR = '\\'; |
+ const PREFIX_SEPARATOR = '_'; |
+ const LOAD_NS = 'namespaces'; |
+ const LOAD_PREFIX = 'prefixes'; |
+ const ACT_AS_FALLBACK = 'fallback_autoloader'; |
+ const AUTOREGISTER_ZF = 'autoregister_zf'; |
+ |
+ /** |
+ * @var array Namespace/directory pairs to search; ZF library added by default |
+ */ |
+ protected $namespaces = array(); |
+ |
+ /** |
+ * @var array Prefix/directory pairs to search |
+ */ |
+ protected $prefixes = array(); |
+ |
+ /** |
+ * @var bool Whether or not the autoloader should also act as a fallback autoloader |
+ */ |
+ protected $fallbackAutoloaderFlag = false; |
+ |
+ /** |
+ * Constructor |
+ * |
+ * @param null|array|\Traversable $options |
+ */ |
+ public function __construct($options = null) |
+ { |
+ if (null !== $options) { |
+ $this->setOptions($options); |
+ } |
+ } |
+ |
+ /** |
+ * Configure autoloader |
+ * |
+ * Allows specifying both "namespace" and "prefix" pairs, using the |
+ * following structure: |
+ * <code> |
+ * array( |
+ * 'namespaces' => array( |
+ * 'Zend' => '/path/to/Zend/library', |
+ * 'Doctrine' => '/path/to/Doctrine/library', |
+ * ), |
+ * 'prefixes' => array( |
+ * 'Phly_' => '/path/to/Phly/library', |
+ * ), |
+ * 'fallback_autoloader' => true, |
+ * ) |
+ * </code> |
+ * |
+ * @param array|\Traversable $options |
+ * @throws Exception\InvalidArgumentException |
+ * @return StandardAutoloader |
+ */ |
+ public function setOptions($options) |
+ { |
+ if (!is_array($options) && !($options instanceof \Traversable)) { |
+ require_once __DIR__ . '/Exception/InvalidArgumentException.php'; |
+ throw new Exception\InvalidArgumentException('Options must be either an array or Traversable'); |
+ } |
+ |
+ foreach ($options as $type => $pairs) { |
+ switch ($type) { |
+ case self::AUTOREGISTER_ZF: |
+ if ($pairs) { |
+ $this->registerNamespace('Zend', dirname(__DIR__)); |
+ } |
+ break; |
+ case self::LOAD_NS: |
+ if (is_array($pairs) || $pairs instanceof \Traversable) { |
+ $this->registerNamespaces($pairs); |
+ } |
+ break; |
+ case self::LOAD_PREFIX: |
+ if (is_array($pairs) || $pairs instanceof \Traversable) { |
+ $this->registerPrefixes($pairs); |
+ } |
+ break; |
+ case self::ACT_AS_FALLBACK: |
+ $this->setFallbackAutoloader($pairs); |
+ break; |
+ default: |
+ // ignore |
+ } |
+ } |
+ return $this; |
+ } |
+ |
+ /** |
+ * Set flag indicating fallback autoloader status |
+ * |
+ * @param bool $flag |
+ * @return StandardAutoloader |
+ */ |
+ public function setFallbackAutoloader($flag) |
+ { |
+ $this->fallbackAutoloaderFlag = (bool) $flag; |
+ return $this; |
+ } |
+ |
+ /** |
+ * Is this autoloader acting as a fallback autoloader? |
+ * |
+ * @return bool |
+ */ |
+ public function isFallbackAutoloader() |
+ { |
+ return $this->fallbackAutoloaderFlag; |
+ } |
+ |
+ /** |
+ * Register a namespace/directory pair |
+ * |
+ * @param string $namespace |
+ * @param string $directory |
+ * @return StandardAutoloader |
+ */ |
+ public function registerNamespace($namespace, $directory) |
+ { |
+ $namespace = rtrim($namespace, self::NS_SEPARATOR) . self::NS_SEPARATOR; |
+ $this->namespaces[$namespace] = $this->normalizeDirectory($directory); |
+ return $this; |
+ } |
+ |
+ /** |
+ * Register many namespace/directory pairs at once |
+ * |
+ * @param array $namespaces |
+ * @throws Exception\InvalidArgumentException |
+ * @return StandardAutoloader |
+ */ |
+ public function registerNamespaces($namespaces) |
+ { |
+ if (!is_array($namespaces) && !$namespaces instanceof \Traversable) { |
+ require_once __DIR__ . '/Exception/InvalidArgumentException.php'; |
+ throw new Exception\InvalidArgumentException('Namespace pairs must be either an array or Traversable'); |
+ } |
+ |
+ foreach ($namespaces as $namespace => $directory) { |
+ $this->registerNamespace($namespace, $directory); |
+ } |
+ return $this; |
+ } |
+ |
+ /** |
+ * Register a prefix/directory pair |
+ * |
+ * @param string $prefix |
+ * @param string $directory |
+ * @return StandardAutoloader |
+ */ |
+ public function registerPrefix($prefix, $directory) |
+ { |
+ $prefix = rtrim($prefix, self::PREFIX_SEPARATOR). self::PREFIX_SEPARATOR; |
+ $this->prefixes[$prefix] = $this->normalizeDirectory($directory); |
+ return $this; |
+ } |
+ |
+ /** |
+ * Register many namespace/directory pairs at once |
+ * |
+ * @param array $prefixes |
+ * @throws Exception\InvalidArgumentException |
+ * @return StandardAutoloader |
+ */ |
+ public function registerPrefixes($prefixes) |
+ { |
+ if (!is_array($prefixes) && !$prefixes instanceof \Traversable) { |
+ require_once __DIR__ . '/Exception/InvalidArgumentException.php'; |
+ throw new Exception\InvalidArgumentException('Prefix pairs must be either an array or Traversable'); |
+ } |
+ |
+ foreach ($prefixes as $prefix => $directory) { |
+ $this->registerPrefix($prefix, $directory); |
+ } |
+ return $this; |
+ } |
+ |
+ /** |
+ * Defined by Autoloadable; autoload a class |
+ * |
+ * @param string $class |
+ * @return false|string |
+ */ |
+ public function autoload($class) |
+ { |
+ $isFallback = $this->isFallbackAutoloader(); |
+ if (false !== strpos($class, self::NS_SEPARATOR)) { |
+ if ($this->loadClass($class, self::LOAD_NS)) { |
+ return $class; |
+ } elseif ($isFallback) { |
+ return $this->loadClass($class, self::ACT_AS_FALLBACK); |
+ } |
+ return false; |
+ } |
+ if (false !== strpos($class, self::PREFIX_SEPARATOR)) { |
+ if ($this->loadClass($class, self::LOAD_PREFIX)) { |
+ return $class; |
+ } elseif ($isFallback) { |
+ return $this->loadClass($class, self::ACT_AS_FALLBACK); |
+ } |
+ return false; |
+ } |
+ if ($isFallback) { |
+ return $this->loadClass($class, self::ACT_AS_FALLBACK); |
+ } |
+ return false; |
+ } |
+ |
+ /** |
+ * Register the autoloader with spl_autoload |
+ * |
+ * @return void |
+ */ |
+ public function register() |
+ { |
+ spl_autoload_register(array($this, 'autoload')); |
+ } |
+ |
+ /** |
+ * Transform the class name to a filename |
+ * |
+ * @param string $class |
+ * @param string $directory |
+ * @return string |
+ */ |
+ protected function transformClassNameToFilename($class, $directory) |
+ { |
+ // $class may contain a namespace portion, in which case we need |
+ // to preserve any underscores in that portion. |
+ $matches = array(); |
+ preg_match('/(?P<namespace>.+\\\)?(?P<class>[^\\\]+$)/', $class, $matches); |
+ |
+ $class = (isset($matches['class'])) ? $matches['class'] : ''; |
+ $namespace = (isset($matches['namespace'])) ? $matches['namespace'] : ''; |
+ |
+ return $directory |
+ . str_replace(self::NS_SEPARATOR, '/', $namespace) |
+ . str_replace(self::PREFIX_SEPARATOR, '/', $class) |
+ . '.php'; |
+ } |
+ |
+ /** |
+ * Load a class, based on its type (namespaced or prefixed) |
+ * |
+ * @param string $class |
+ * @param string $type |
+ * @return bool|string |
+ * @throws Exception\InvalidArgumentException |
+ */ |
+ protected function loadClass($class, $type) |
+ { |
+ if (!in_array($type, array(self::LOAD_NS, self::LOAD_PREFIX, self::ACT_AS_FALLBACK))) { |
+ require_once __DIR__ . '/Exception/InvalidArgumentException.php'; |
+ throw new Exception\InvalidArgumentException(); |
+ } |
+ |
+ // Fallback autoloading |
+ if ($type === self::ACT_AS_FALLBACK) { |
+ // create filename |
+ $filename = $this->transformClassNameToFilename($class, ''); |
+ $resolvedName = stream_resolve_include_path($filename); |
+ if ($resolvedName !== false) { |
+ return include $resolvedName; |
+ } |
+ return false; |
+ } |
+ |
+ // Namespace and/or prefix autoloading |
+ foreach ($this->$type as $leader => $path) { |
+ if (0 === strpos($class, $leader)) { |
+ // Trim off leader (namespace or prefix) |
+ $trimmedClass = substr($class, strlen($leader)); |
+ |
+ // create filename |
+ $filename = $this->transformClassNameToFilename($trimmedClass, $path); |
+ if (file_exists($filename)) { |
+ return include $filename; |
+ } |
+ return false; |
+ } |
+ } |
+ return false; |
+ } |
+ |
+ /** |
+ * Normalize the directory to include a trailing directory separator |
+ * |
+ * @param string $directory |
+ * @return string |
+ */ |
+ protected function normalizeDirectory($directory) |
+ { |
+ $last = $directory[strlen($directory) - 1]; |
+ if (in_array($last, array('/', '\\'))) { |
+ $directory[strlen($directory) - 1] = DIRECTORY_SEPARATOR; |
+ return $directory; |
+ } |
+ $directory .= DIRECTORY_SEPARATOR; |
+ return $directory; |
+ } |
+} |