PluginProbe
WP Debugging / 2.11.19
WP Debugging v2.11.19
2.12.6 2.12.5 trunk 2.10.0 2.10.1 2.10.2 2.11.0 2.11.1 2.11.10 2.11.11 2.11.12 2.11.13 2.11.14 2.11.15 2.11.16 2.11.17 2.11.18 2.11.19 2.11.2 2.11.20 2.11.21 2.11.22 2.11.23 2.11.24 2.11.3 All 59 releases
wp-debugging / vendor / composer / ClassLoader.php

ClassLoader.php in WP Debugging 2.11.19, at vendor/composer/ClassLoader.php

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