composer package updates
[openemr.git] / vendor / zendframework / zend-loader / src / StandardAutoloader.php
blobbab0b390a25a845345952e68ea08bdb67a2cb09b
1 <?php
2 /**
3 * @see https://github.com/zendframework/zend-loader for the canonical source repository
4 * @copyright Copyright (c) 2005-2018 Zend Technologies USA Inc. (https://www.zend.com)
5 * @license https://github.com/zendframework/zend-loader/blob/master/LICENSE.md New BSD License
6 */
8 namespace Zend\Loader;
10 // Grab SplAutoloader interface
11 require_once __DIR__ . '/SplAutoloader.php';
13 /**
14 * PSR-0 compliant autoloader
16 * Allows autoloading both namespaced and vendor-prefixed classes. Class
17 * lookups are performed on the filesystem. If a class file for the referenced
18 * class is not found, a PHP warning will be raised by include().
20 class StandardAutoloader implements SplAutoloader
22 const NS_SEPARATOR = '\\';
23 const PREFIX_SEPARATOR = '_';
24 const LOAD_NS = 'namespaces';
25 const LOAD_PREFIX = 'prefixes';
26 const ACT_AS_FALLBACK = 'fallback_autoloader';
27 const AUTOREGISTER_ZF = 'autoregister_zf';
29 /**
30 * @var array Namespace/directory pairs to search; ZF library added by default
32 protected $namespaces = [];
34 /**
35 * @var array Prefix/directory pairs to search
37 protected $prefixes = [];
39 /**
40 * @var bool Whether or not the autoloader should also act as a fallback autoloader
42 protected $fallbackAutoloaderFlag = false;
44 /**
45 * Constructor
47 * @param null|array|\Traversable $options
49 public function __construct($options = null)
51 if (null !== $options) {
52 $this->setOptions($options);
56 /**
57 * Configure autoloader
59 * Allows specifying both "namespace" and "prefix" pairs, using the
60 * following structure:
61 * <code>
62 * array(
63 * 'namespaces' => array(
64 * 'Zend' => '/path/to/Zend/library',
65 * 'Doctrine' => '/path/to/Doctrine/library',
66 * ),
67 * 'prefixes' => array(
68 * 'Phly_' => '/path/to/Phly/library',
69 * ),
70 * 'fallback_autoloader' => true,
71 * )
72 * </code>
74 * @param array|\Traversable $options
75 * @throws Exception\InvalidArgumentException
76 * @return StandardAutoloader
78 public function setOptions($options)
80 if (! is_array($options) && ! ($options instanceof \Traversable)) {
81 require_once __DIR__ . '/Exception/InvalidArgumentException.php';
82 throw new Exception\InvalidArgumentException('Options must be either an array or Traversable');
85 foreach ($options as $type => $pairs) {
86 switch ($type) {
87 case self::AUTOREGISTER_ZF:
88 if ($pairs) {
89 $this->registerNamespace('Zend', dirname(__DIR__));
90 $this->registerNamespace(
91 'ZendXml',
92 dirname(dirname((__DIR__))) . DIRECTORY_SEPARATOR . 'ZendXml'
95 break;
96 case self::LOAD_NS:
97 if (is_array($pairs) || $pairs instanceof \Traversable) {
98 $this->registerNamespaces($pairs);
100 break;
101 case self::LOAD_PREFIX:
102 if (is_array($pairs) || $pairs instanceof \Traversable) {
103 $this->registerPrefixes($pairs);
105 break;
106 case self::ACT_AS_FALLBACK:
107 $this->setFallbackAutoloader($pairs);
108 break;
109 default:
110 // ignore
113 return $this;
117 * Set flag indicating fallback autoloader status
119 * @param bool $flag
120 * @return StandardAutoloader
122 public function setFallbackAutoloader($flag)
124 $this->fallbackAutoloaderFlag = (bool) $flag;
125 return $this;
129 * Is this autoloader acting as a fallback autoloader?
131 * @return bool
133 public function isFallbackAutoloader()
135 return $this->fallbackAutoloaderFlag;
139 * Register a namespace/directory pair
141 * @param string $namespace
142 * @param string $directory
143 * @return StandardAutoloader
145 public function registerNamespace($namespace, $directory)
147 $namespace = rtrim($namespace, self::NS_SEPARATOR) . self::NS_SEPARATOR;
148 $this->namespaces[$namespace] = $this->normalizeDirectory($directory);
149 return $this;
153 * Register many namespace/directory pairs at once
155 * @param array $namespaces
156 * @throws Exception\InvalidArgumentException
157 * @return StandardAutoloader
159 public function registerNamespaces($namespaces)
161 if (! is_array($namespaces) && ! $namespaces instanceof \Traversable) {
162 require_once __DIR__ . '/Exception/InvalidArgumentException.php';
163 throw new Exception\InvalidArgumentException('Namespace pairs must be either an array or Traversable');
166 foreach ($namespaces as $namespace => $directory) {
167 $this->registerNamespace($namespace, $directory);
169 return $this;
173 * Register a prefix/directory pair
175 * @param string $prefix
176 * @param string $directory
177 * @return StandardAutoloader
179 public function registerPrefix($prefix, $directory)
181 $prefix = rtrim($prefix, self::PREFIX_SEPARATOR). self::PREFIX_SEPARATOR;
182 $this->prefixes[$prefix] = $this->normalizeDirectory($directory);
183 return $this;
187 * Register many namespace/directory pairs at once
189 * @param array $prefixes
190 * @throws Exception\InvalidArgumentException
191 * @return StandardAutoloader
193 public function registerPrefixes($prefixes)
195 if (! is_array($prefixes) && ! $prefixes instanceof \Traversable) {
196 require_once __DIR__ . '/Exception/InvalidArgumentException.php';
197 throw new Exception\InvalidArgumentException('Prefix pairs must be either an array or Traversable');
200 foreach ($prefixes as $prefix => $directory) {
201 $this->registerPrefix($prefix, $directory);
203 return $this;
207 * Defined by Autoloadable; autoload a class
209 * @param string $class
210 * @return false|string
212 public function autoload($class)
214 $isFallback = $this->isFallbackAutoloader();
215 if (false !== strpos($class, self::NS_SEPARATOR)) {
216 if ($this->loadClass($class, self::LOAD_NS)) {
217 return $class;
218 } elseif ($isFallback) {
219 return $this->loadClass($class, self::ACT_AS_FALLBACK);
221 return false;
223 if (false !== strpos($class, self::PREFIX_SEPARATOR)) {
224 if ($this->loadClass($class, self::LOAD_PREFIX)) {
225 return $class;
226 } elseif ($isFallback) {
227 return $this->loadClass($class, self::ACT_AS_FALLBACK);
229 return false;
231 if ($isFallback) {
232 return $this->loadClass($class, self::ACT_AS_FALLBACK);
234 return false;
238 * Register the autoloader with spl_autoload
240 * @return void
242 public function register()
244 spl_autoload_register([$this, 'autoload']);
248 * Transform the class name to a filename
250 * @param string $class
251 * @param string $directory
252 * @return string
254 protected function transformClassNameToFilename($class, $directory)
256 // $class may contain a namespace portion, in which case we need
257 // to preserve any underscores in that portion.
258 $matches = [];
259 preg_match('/(?P<namespace>.+\\\)?(?P<class>[^\\\]+$)/', $class, $matches);
261 $class = (isset($matches['class'])) ? $matches['class'] : '';
262 $namespace = (isset($matches['namespace'])) ? $matches['namespace'] : '';
264 return $directory
265 . str_replace(self::NS_SEPARATOR, '/', $namespace)
266 . str_replace(self::PREFIX_SEPARATOR, '/', $class)
267 . '.php';
271 * Load a class, based on its type (namespaced or prefixed)
273 * @param string $class
274 * @param string $type
275 * @return bool|string
276 * @throws Exception\InvalidArgumentException
278 protected function loadClass($class, $type)
280 if (! in_array($type, [self::LOAD_NS, self::LOAD_PREFIX, self::ACT_AS_FALLBACK])) {
281 require_once __DIR__ . '/Exception/InvalidArgumentException.php';
282 throw new Exception\InvalidArgumentException();
285 // Fallback autoloading
286 if ($type === self::ACT_AS_FALLBACK) {
287 // create filename
288 $filename = $this->transformClassNameToFilename($class, '');
289 $resolvedName = stream_resolve_include_path($filename);
290 if ($resolvedName !== false) {
291 return include $resolvedName;
293 return false;
296 // Namespace and/or prefix autoloading
297 foreach ($this->$type as $leader => $path) {
298 if (0 === strpos($class, $leader)) {
299 // Trim off leader (namespace or prefix)
300 $trimmedClass = substr($class, strlen($leader));
302 // create filename
303 $filename = $this->transformClassNameToFilename($trimmedClass, $path);
304 if (file_exists($filename)) {
305 return include $filename;
309 return false;
313 * Normalize the directory to include a trailing directory separator
315 * @param string $directory
316 * @return string
318 protected function normalizeDirectory($directory)
320 $last = $directory[strlen($directory) - 1];
321 if (in_array($last, ['/', '\\'])) {
322 $directory[strlen($directory) - 1] = DIRECTORY_SEPARATOR;
323 return $directory;
325 $directory .= DIRECTORY_SEPARATOR;
326 return $directory;