diff options
Diffstat (limited to 'vendor/composer/ClassLoader.php')
-rw-r--r-- | vendor/composer/ClassLoader.php | 579 |
1 files changed, 579 insertions, 0 deletions
diff --git a/vendor/composer/ClassLoader.php b/vendor/composer/ClassLoader.php new file mode 100644 index 0000000..7824d8f --- /dev/null +++ b/vendor/composer/ClassLoader.php | |||
@@ -0,0 +1,579 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Composer. | ||
5 | * | ||
6 | * (c) Nils Adermann <naderman@naderman.de> | ||
7 | * Jordi Boggiano <j.boggiano@seld.be> | ||
8 | * | ||
9 | * For the full copyright and license information, please view the LICENSE | ||
10 | * file that was distributed with this source code. | ||
11 | */ | ||
12 | |||
13 | namespace Composer\Autoload; | ||
14 | |||
15 | /** | ||
16 | * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. | ||
17 | * | ||
18 | * $loader = new \Composer\Autoload\ClassLoader(); | ||
19 | * | ||
20 | * // register classes with namespaces | ||
21 | * $loader->add('Symfony\Component', __DIR__.'/component'); | ||
22 | * $loader->add('Symfony', __DIR__.'/framework'); | ||
23 | * | ||
24 | * // activate the autoloader | ||
25 | * $loader->register(); | ||
26 | * | ||
27 | * // to enable searching the include path (eg. for PEAR packages) | ||
28 | * $loader->setUseIncludePath(true); | ||
29 | * | ||
30 | * In this example, if you try to use a class in the Symfony\Component | ||
31 | * namespace or one of its children (Symfony\Component\Console for instance), | ||
32 | * the autoloader will first look for the class under the component/ | ||
33 | * directory, and it will then fallback to the framework/ directory if not | ||
34 | * found before giving up. | ||
35 | * | ||
36 | * This class is loosely based on the Symfony UniversalClassLoader. | ||
37 | * | ||
38 | * @author Fabien Potencier <fabien@symfony.com> | ||
39 | * @author Jordi Boggiano <j.boggiano@seld.be> | ||
40 | * @see https://www.php-fig.org/psr/psr-0/ | ||
41 | * @see https://www.php-fig.org/psr/psr-4/ | ||
42 | */ | ||
43 | class ClassLoader | ||
44 | { | ||
45 | /** @var \Closure(string):void */ | ||
46 | private static $includeFile; | ||
47 | |||
48 | /** @var string|null */ | ||
49 | private $vendorDir; | ||
50 | |||
51 | // PSR-4 | ||
52 | /** | ||
53 | * @var array<string, array<string, int>> | ||
54 | */ | ||
55 | private $prefixLengthsPsr4 = array(); | ||
56 | /** | ||
57 | * @var array<string, list<string>> | ||
58 | */ | ||
59 | private $prefixDirsPsr4 = array(); | ||
60 | /** | ||
61 | * @var list<string> | ||
62 | */ | ||
63 | private $fallbackDirsPsr4 = array(); | ||
64 | |||
65 | // PSR-0 | ||
66 | /** | ||
67 | * List of PSR-0 prefixes | ||
68 | * | ||
69 | * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2'))) | ||
70 | * | ||
71 | * @var array<string, array<string, list<string>>> | ||
72 | */ | ||
73 | private $prefixesPsr0 = array(); | ||
74 | /** | ||
75 | * @var list<string> | ||
76 | */ | ||
77 | private $fallbackDirsPsr0 = array(); | ||
78 | |||
79 | /** @var bool */ | ||
80 | private $useIncludePath = false; | ||
81 | |||
82 | /** | ||
83 | * @var array<string, string> | ||
84 | */ | ||
85 | private $classMap = array(); | ||
86 | |||
87 | /** @var bool */ | ||
88 | private $classMapAuthoritative = false; | ||
89 | |||
90 | /** | ||
91 | * @var array<string, bool> | ||
92 | */ | ||
93 | private $missingClasses = array(); | ||
94 | |||
95 | /** @var string|null */ | ||
96 | private $apcuPrefix; | ||
97 | |||
98 | /** | ||
99 | * @var array<string, self> | ||
100 | */ | ||
101 | private static $registeredLoaders = array(); | ||
102 | |||
103 | /** | ||
104 | * @param string|null $vendorDir | ||
105 | */ | ||
106 | public function __construct($vendorDir = null) | ||
107 | { | ||
108 | $this->vendorDir = $vendorDir; | ||
109 | self::initializeIncludeClosure(); | ||
110 | } | ||
111 | |||
112 | /** | ||
113 | * @return array<string, list<string>> | ||
114 | */ | ||
115 | public function getPrefixes() | ||
116 | { | ||
117 | if (!empty($this->prefixesPsr0)) { | ||
118 | return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); | ||
119 | } | ||
120 | |||
121 | return array(); | ||
122 | } | ||
123 | |||
124 | /** | ||
125 | * @return array<string, list<string>> | ||
126 | */ | ||
127 | public function getPrefixesPsr4() | ||
128 | { | ||
129 | return $this->prefixDirsPsr4; | ||
130 | } | ||
131 | |||
132 | /** | ||
133 | * @return list<string> | ||
134 | */ | ||
135 | public function getFallbackDirs() | ||
136 | { | ||
137 | return $this->fallbackDirsPsr0; | ||
138 | } | ||
139 | |||
140 | /** | ||
141 | * @return list<string> | ||
142 | */ | ||
143 | public function getFallbackDirsPsr4() | ||
144 | { | ||
145 | return $this->fallbackDirsPsr4; | ||
146 | } | ||
147 | |||
148 | /** | ||
149 | * @return array<string, string> Array of classname => path | ||
150 | */ | ||
151 | public function getClassMap() | ||
152 | { | ||
153 | return $this->classMap; | ||
154 | } | ||
155 | |||
156 | /** | ||
157 | * @param array<string, string> $classMap Class to filename map | ||
158 | * | ||
159 | * @return void | ||
160 | */ | ||
161 | public function addClassMap(array $classMap) | ||
162 | { | ||
163 | if ($this->classMap) { | ||
164 | $this->classMap = array_merge($this->classMap, $classMap); | ||
165 | } else { | ||
166 | $this->classMap = $classMap; | ||
167 | } | ||
168 | } | ||
169 | |||
170 | /** | ||
171 | * Registers a set of PSR-0 directories for a given prefix, either | ||
172 | * appending or prepending to the ones previously set for this prefix. | ||
173 | * | ||
174 | * @param string $prefix The prefix | ||
175 | * @param list<string>|string $paths The PSR-0 root directories | ||
176 | * @param bool $prepend Whether to prepend the directories | ||
177 | * | ||
178 | * @return void | ||
179 | */ | ||
180 | public function add($prefix, $paths, $prepend = false) | ||
181 | { | ||
182 | $paths = (array) $paths; | ||
183 | if (!$prefix) { | ||
184 | if ($prepend) { | ||
185 | $this->fallbackDirsPsr0 = array_merge( | ||
186 | $paths, | ||
187 | $this->fallbackDirsPsr0 | ||
188 | ); | ||
189 | } else { | ||
190 | $this->fallbackDirsPsr0 = array_merge( | ||
191 | $this->fallbackDirsPsr0, | ||
192 | $paths | ||
193 | ); | ||
194 | } | ||
195 | |||
196 | return; | ||
197 | } | ||
198 | |||
199 | $first = $prefix[0]; | ||
200 | if (!isset($this->prefixesPsr0[$first][$prefix])) { | ||
201 | $this->prefixesPsr0[$first][$prefix] = $paths; | ||
202 | |||
203 | return; | ||
204 | } | ||
205 | if ($prepend) { | ||
206 | $this->prefixesPsr0[$first][$prefix] = array_merge( | ||
207 | $paths, | ||
208 | $this->prefixesPsr0[$first][$prefix] | ||
209 | ); | ||
210 | } else { | ||
211 | $this->prefixesPsr0[$first][$prefix] = array_merge( | ||
212 | $this->prefixesPsr0[$first][$prefix], | ||
213 | $paths | ||
214 | ); | ||
215 | } | ||
216 | } | ||
217 | |||
218 | /** | ||
219 | * Registers a set of PSR-4 directories for a given namespace, either | ||
220 | * appending or prepending to the ones previously set for this namespace. | ||
221 | * | ||
222 | * @param string $prefix The prefix/namespace, with trailing '\\' | ||
223 | * @param list<string>|string $paths The PSR-4 base directories | ||
224 | * @param bool $prepend Whether to prepend the directories | ||
225 | * | ||
226 | * @throws \InvalidArgumentException | ||
227 | * | ||
228 | * @return void | ||
229 | */ | ||
230 | public function addPsr4($prefix, $paths, $prepend = false) | ||
231 | { | ||
232 | $paths = (array) $paths; | ||
233 | if (!$prefix) { | ||
234 | // Register directories for the root namespace. | ||
235 | if ($prepend) { | ||
236 | $this->fallbackDirsPsr4 = array_merge( | ||
237 | $paths, | ||
238 | $this->fallbackDirsPsr4 | ||
239 | ); | ||
240 | } else { | ||
241 | $this->fallbackDirsPsr4 = array_merge( | ||
242 | $this->fallbackDirsPsr4, | ||
243 | $paths | ||
244 | ); | ||
245 | } | ||
246 | } elseif (!isset($this->prefixDirsPsr4[$prefix])) { | ||
247 | // Register directories for a new namespace. | ||
248 | $length = strlen($prefix); | ||
249 | if ('\\' !== $prefix[$length - 1]) { | ||
250 | throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); | ||
251 | } | ||
252 | $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; | ||
253 | $this->prefixDirsPsr4[$prefix] = $paths; | ||
254 | } elseif ($prepend) { | ||
255 | // Prepend directories for an already registered namespace. | ||
256 | $this->prefixDirsPsr4[$prefix] = array_merge( | ||
257 | $paths, | ||
258 | $this->prefixDirsPsr4[$prefix] | ||
259 | ); | ||
260 | } else { | ||
261 | // Append directories for an already registered namespace. | ||
262 | $this->prefixDirsPsr4[$prefix] = array_merge( | ||
263 | $this->prefixDirsPsr4[$prefix], | ||
264 | $paths | ||
265 | ); | ||
266 | } | ||
267 | } | ||
268 | |||
269 | /** | ||
270 | * Registers a set of PSR-0 directories for a given prefix, | ||
271 | * replacing any others previously set for this prefix. | ||
272 | * | ||
273 | * @param string $prefix The prefix | ||
274 | * @param list<string>|string $paths The PSR-0 base directories | ||
275 | * | ||
276 | * @return void | ||
277 | */ | ||
278 | public function set($prefix, $paths) | ||
279 | { | ||
280 | if (!$prefix) { | ||
281 | $this->fallbackDirsPsr0 = (array) $paths; | ||
282 | } else { | ||
283 | $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; | ||
284 | } | ||
285 | } | ||
286 | |||
287 | /** | ||
288 | * Registers a set of PSR-4 directories for a given namespace, | ||
289 | * replacing any others previously set for this namespace. | ||
290 | * | ||
291 | * @param string $prefix The prefix/namespace, with trailing '\\' | ||
292 | * @param list<string>|string $paths The PSR-4 base directories | ||
293 | * | ||
294 | * @throws \InvalidArgumentException | ||
295 | * | ||
296 | * @return void | ||
297 | */ | ||
298 | public function setPsr4($prefix, $paths) | ||
299 | { | ||
300 | if (!$prefix) { | ||
301 | $this->fallbackDirsPsr4 = (array) $paths; | ||
302 | } else { | ||
303 | $length = strlen($prefix); | ||
304 | if ('\\' !== $prefix[$length - 1]) { | ||
305 | throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); | ||
306 | } | ||
307 | $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; | ||
308 | $this->prefixDirsPsr4[$prefix] = (array) $paths; | ||
309 | } | ||
310 | } | ||
311 | |||
312 | /** | ||
313 | * Turns on searching the include path for class files. | ||
314 | * | ||
315 | * @param bool $useIncludePath | ||
316 | * | ||
317 | * @return void | ||
318 | */ | ||
319 | public function setUseIncludePath($useIncludePath) | ||
320 | { | ||
321 | $this->useIncludePath = $useIncludePath; | ||
322 | } | ||
323 | |||
324 | /** | ||
325 | * Can be used to check if the autoloader uses the include path to check | ||
326 | * for classes. | ||
327 | * | ||
328 | * @return bool | ||
329 | */ | ||
330 | public function getUseIncludePath() | ||
331 | { | ||
332 | return $this->useIncludePath; | ||
333 | } | ||
334 | |||
335 | /** | ||
336 | * Turns off searching the prefix and fallback directories for classes | ||
337 | * that have not been registered with the class map. | ||
338 | * | ||
339 | * @param bool $classMapAuthoritative | ||
340 | * | ||
341 | * @return void | ||
342 | */ | ||
343 | public function setClassMapAuthoritative($classMapAuthoritative) | ||
344 | { | ||
345 | $this->classMapAuthoritative = $classMapAuthoritative; | ||
346 | } | ||
347 | |||
348 | /** | ||
349 | * Should class lookup fail if not found in the current class map? | ||
350 | * | ||
351 | * @return bool | ||
352 | */ | ||
353 | public function isClassMapAuthoritative() | ||
354 | { | ||
355 | return $this->classMapAuthoritative; | ||
356 | } | ||
357 | |||
358 | /** | ||
359 | * APCu prefix to use to cache found/not-found classes, if the extension is enabled. | ||
360 | * | ||
361 | * @param string|null $apcuPrefix | ||
362 | * | ||
363 | * @return void | ||
364 | */ | ||
365 | public function setApcuPrefix($apcuPrefix) | ||
366 | { | ||
367 | $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; | ||
368 | } | ||
369 | |||
370 | /** | ||
371 | * The APCu prefix in use, or null if APCu caching is not enabled. | ||
372 | * | ||
373 | * @return string|null | ||
374 | */ | ||
375 | public function getApcuPrefix() | ||
376 | { | ||
377 | return $this->apcuPrefix; | ||
378 | } | ||
379 | |||
380 | /** | ||
381 | * Registers this instance as an autoloader. | ||
382 | * | ||
383 | * @param bool $prepend Whether to prepend the autoloader or not | ||
384 | * | ||
385 | * @return void | ||
386 | */ | ||
387 | public function register($prepend = false) | ||
388 | { | ||
389 | spl_autoload_register(array($this, 'loadClass'), true, $prepend); | ||
390 | |||
391 | if (null === $this->vendorDir) { | ||
392 | return; | ||
393 | } | ||
394 | |||
395 | if ($prepend) { | ||
396 | self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; | ||
397 | } else { | ||
398 | unset(self::$registeredLoaders[$this->vendorDir]); | ||
399 | self::$registeredLoaders[$this->vendorDir] = $this; | ||
400 | } | ||
401 | } | ||
402 | |||
403 | /** | ||
404 | * Unregisters this instance as an autoloader. | ||
405 | * | ||
406 | * @return void | ||
407 | */ | ||
408 | public function unregister() | ||
409 | { | ||
410 | spl_autoload_unregister(array($this, 'loadClass')); | ||
411 | |||
412 | if (null !== $this->vendorDir) { | ||
413 | unset(self::$registeredLoaders[$this->vendorDir]); | ||
414 | } | ||
415 | } | ||
416 | |||
417 | /** | ||
418 | * Loads the given class or interface. | ||
419 | * | ||
420 | * @param string $class The name of the class | ||
421 | * @return true|null True if loaded, null otherwise | ||
422 | */ | ||
423 | public function loadClass($class) | ||
424 | { | ||
425 | if ($file = $this->findFile($class)) { | ||
426 | $includeFile = self::$includeFile; | ||
427 | $includeFile($file); | ||
428 | |||
429 | return true; | ||
430 | } | ||
431 | |||
432 | return null; | ||
433 | } | ||
434 | |||
435 | /** | ||
436 | * Finds the path to the file where the class is defined. | ||
437 | * | ||
438 | * @param string $class The name of the class | ||
439 | * | ||
440 | * @return string|false The path if found, false otherwise | ||
441 | */ | ||
442 | public function findFile($class) | ||
443 | { | ||
444 | // class map lookup | ||
445 | if (isset($this->classMap[$class])) { | ||
446 | return $this->classMap[$class]; | ||
447 | } | ||
448 | if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { | ||
449 | return false; | ||
450 | } | ||
451 | if (null !== $this->apcuPrefix) { | ||
452 | $file = apcu_fetch($this->apcuPrefix.$class, $hit); | ||
453 | if ($hit) { | ||
454 | return $file; | ||
455 | } | ||
456 | } | ||
457 | |||
458 | $file = $this->findFileWithExtension($class, '.php'); | ||
459 | |||
460 | // Search for Hack files if we are running on HHVM | ||
461 | if (false === $file && defined('HHVM_VERSION')) { | ||
462 | $file = $this->findFileWithExtension($class, '.hh'); | ||
463 | } | ||
464 | |||
465 | if (null !== $this->apcuPrefix) { | ||
466 | apcu_add($this->apcuPrefix.$class, $file); | ||
467 | } | ||
468 | |||
469 | if (false === $file) { | ||
470 | // Remember that this class does not exist. | ||
471 | $this->missingClasses[$class] = true; | ||
472 | } | ||
473 | |||
474 | return $file; | ||
475 | } | ||
476 | |||
477 | /** | ||
478 | * Returns the currently registered loaders keyed by their corresponding vendor directories. | ||
479 | * | ||
480 | * @return array<string, self> | ||
481 | */ | ||
482 | public static function getRegisteredLoaders() | ||
483 | { | ||
484 | return self::$registeredLoaders; | ||
485 | } | ||
486 | |||
487 | /** | ||
488 | * @param string $class | ||
489 | * @param string $ext | ||
490 | * @return string|false | ||
491 | */ | ||
492 | private function findFileWithExtension($class, $ext) | ||
493 | { | ||
494 | // PSR-4 lookup | ||
495 | $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; | ||
496 | |||
497 | $first = $class[0]; | ||
498 | if (isset($this->prefixLengthsPsr4[$first])) { | ||
499 | $subPath = $class; | ||
500 | while (false !== $lastPos = strrpos($subPath, '\\')) { | ||
501 | $subPath = substr($subPath, 0, $lastPos); | ||
502 | $search = $subPath . '\\'; | ||
503 | if (isset($this->prefixDirsPsr4[$search])) { | ||
504 | $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); | ||
505 | foreach ($this->prefixDirsPsr4[$search] as $dir) { | ||
506 | if (file_exists($file = $dir . $pathEnd)) { | ||
507 | return $file; | ||
508 | } | ||
509 | } | ||
510 | } | ||
511 | } | ||
512 | } | ||
513 | |||
514 | // PSR-4 fallback dirs | ||
515 | foreach ($this->fallbackDirsPsr4 as $dir) { | ||
516 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { | ||
517 | return $file; | ||
518 | } | ||
519 | } | ||
520 | |||
521 | // PSR-0 lookup | ||
522 | if (false !== $pos = strrpos($class, '\\')) { | ||
523 | // namespaced class name | ||
524 | $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) | ||
525 | . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); | ||
526 | } else { | ||
527 | // PEAR-like class name | ||
528 | $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; | ||
529 | } | ||
530 | |||
531 | if (isset($this->prefixesPsr0[$first])) { | ||
532 | foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { | ||
533 | if (0 === strpos($class, $prefix)) { | ||
534 | foreach ($dirs as $dir) { | ||
535 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { | ||
536 | return $file; | ||
537 | } | ||
538 | } | ||
539 | } | ||
540 | } | ||
541 | } | ||
542 | |||
543 | // PSR-0 fallback dirs | ||
544 | foreach ($this->fallbackDirsPsr0 as $dir) { | ||
545 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { | ||
546 | return $file; | ||
547 | } | ||
548 | } | ||
549 | |||
550 | // PSR-0 include paths. | ||
551 | if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { | ||
552 | return $file; | ||
553 | } | ||
554 | |||
555 | return false; | ||
556 | } | ||
557 | |||
558 | /** | ||
559 | * @return void | ||
560 | */ | ||
561 | private static function initializeIncludeClosure() | ||
562 | { | ||
563 | if (self::$includeFile !== null) { | ||
564 | return; | ||
565 | } | ||
566 | |||
567 | /** | ||
568 | * Scope isolated include. | ||
569 | * | ||
570 | * Prevents access to $this/self from included files. | ||
571 | * | ||
572 | * @param string $file | ||
573 | * @return void | ||
574 | */ | ||
575 | self::$includeFile = \Closure::bind(static function($file) { | ||
576 | include $file; | ||
577 | }, null, null); | ||
578 | } | ||
579 | } | ||