PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.11.10
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.11.10
4.0.8 4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.10.1 3.10.10 3.10.11 3.10.12 3.10.13 3.10.14 3.10.15 3.10.2 3.10.3 All 149 releases
← All changes | vendor/composer/ClassLoader.php +214 -48 3.1.03.11.10 View file →
@@ -36,51 +36,119 @@
36 36 * This class is loosely based on the Symfony UniversalClassLoader.
37 37 *
38 38 * @author Fabien Potencier <fabien@symfony.com>
39 39 * @author Jordi Boggiano <j.boggiano@seld.be>
40 - * @see http://www.php-fig.org/psr/psr-0/
41 - * @see http://www.php-fig.org/psr/psr-4/
40 + * @see https://www.php-fig.org/psr/psr-0/
41 + * @see https://www.php-fig.org/psr/psr-4/
42 42 */
43 43 class ClassLoader
44 44 {
45 + /** @var \Closure(string):void */
46 + private static $includeFile;
47 +
48 + /** @var string|null */
49 + private $vendorDir;
50 +
45 51 // PSR-4
52 + /**
53 + * @var array<string, array<string, int>>
54 + */
46 55 private $prefixLengthsPsr4 = array();
56 + /**
57 + * @var array<string, list<string>>
58 + */
47 59 private $prefixDirsPsr4 = array();
60 + /**
61 + * @var list<string>
62 + */
48 63 private $fallbackDirsPsr4 = array();
49 64
50 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 + */
51 73 private $prefixesPsr0 = array();
74 + /**
75 + * @var list<string>
76 + */
52 77 private $fallbackDirsPsr0 = array();
53 78
79 + /** @var bool */
54 80 private $useIncludePath = false;
81 +
82 + /**
83 + * @var array<string, string>
84 + */
55 85 private $classMap = array();
56 86
87 + /** @var bool */
57 88 private $classMapAuthoritative = false;
58 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 + */
59 115 public function getPrefixes()
60 116 {
61 117 if (!empty($this->prefixesPsr0)) {
62 - return call_user_func_array('array_merge', $this->prefixesPsr0);
118 + return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
63 119 }
64 120
65 121 return array();
66 122 }
67 123
124 + /**
125 + * @return array<string, list<string>>
126 + */
68 127 public function getPrefixesPsr4()
69 128 {
70 129 return $this->prefixDirsPsr4;
71 130 }
72 131
132 + /**
133 + * @return list<string>
134 + */
73 135 public function getFallbackDirs()
74 136 {
75 137 return $this->fallbackDirsPsr0;
76 138 }
77 139
140 + /**
141 + * @return list<string>
142 + */
78 143 public function getFallbackDirsPsr4()
79 144 {
80 145 return $this->fallbackDirsPsr4;
81 146 }
82 147
148 + /**
149 + * @return array<string, string> Array of classname => path
150 + */
83 151 public function getClassMap()
84 152 {
85 153 return $this->classMap;
86 154 }
@@ -85,9 +153,11 @@
85 153 return $this->classMap;
86 154 }
87 155
88 156 /**
89 - * @param array $classMap Class to filename map
157 + * @param array<string, string> $classMap Class to filename map
158 + *
159 + * @return void
90 160 */
91 161 public function addClassMap(array $classMap)
92 162 {
93 163 if ($this->classMap) {
@@ -100,24 +170,27 @@
100 170 /**
101 171 * Registers a set of PSR-0 directories for a given prefix, either
102 172 * appending or prepending to the ones previously set for this prefix.
103 173 *
104 - * @param string $prefix The prefix
105 - * @param array|string $paths The PSR-0 root directories
106 - * @param bool $prepend Whether to prepend the directories
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
107 179 */
108 180 public function add($prefix, $paths, $prepend = false)
109 181 {
182 + $paths = (array) $paths;
110 183 if (!$prefix) {
111 184 if ($prepend) {
112 185 $this->fallbackDirsPsr0 = array_merge(
113 - (array) $paths,
186 + $paths,
114 187 $this->fallbackDirsPsr0
115 188 );
116 189 } else {
117 190 $this->fallbackDirsPsr0 = array_merge(
118 191 $this->fallbackDirsPsr0,
119 - (array) $paths
192 + $paths
120 193 );
121 194 }
122 195
123 196 return;
@@ -124,21 +197,21 @@
124 197 }
125 198
126 199 $first = $prefix[0];
127 200 if (!isset($this->prefixesPsr0[$first][$prefix])) {
128 - $this->prefixesPsr0[$first][$prefix] = (array) $paths;
201 + $this->prefixesPsr0[$first][$prefix] = $paths;
129 202
130 203 return;
131 204 }
132 205 if ($prepend) {
133 206 $this->prefixesPsr0[$first][$prefix] = array_merge(
134 - (array) $paths,
207 + $paths,
135 208 $this->prefixesPsr0[$first][$prefix]
136 209 );
137 210 } else {
138 211 $this->prefixesPsr0[$first][$prefix] = array_merge(
139 212 $this->prefixesPsr0[$first][$prefix],
140 - (array) $paths
213 + $paths
141 214 );
142 215 }
143 216 }
144 217
@@ -145,27 +218,30 @@
145 218 /**
146 219 * Registers a set of PSR-4 directories for a given namespace, either
147 220 * appending or prepending to the ones previously set for this namespace.
148 221 *
149 - * @param string $prefix The prefix/namespace, with trailing '\\'
150 - * @param array|string $paths The PSR-4 base directories
151 - * @param bool $prepend Whether to prepend the directories
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
152 225 *
153 226 * @throws \InvalidArgumentException
227 + *
228 + * @return void
154 229 */
155 230 public function addPsr4($prefix, $paths, $prepend = false)
156 231 {
232 + $paths = (array) $paths;
157 233 if (!$prefix) {
158 234 // Register directories for the root namespace.
159 235 if ($prepend) {
160 236 $this->fallbackDirsPsr4 = array_merge(
161 - (array) $paths,
237 + $paths,
162 238 $this->fallbackDirsPsr4
163 239 );
164 240 } else {
165 241 $this->fallbackDirsPsr4 = array_merge(
166 242 $this->fallbackDirsPsr4,
167 - (array) $paths
243 + $paths
168 244 );
169 245 }
170 246 } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
171 247 // Register directories for a new namespace.
@@ -173,13 +249,13 @@
173 249 if ('\\' !== $prefix[$length - 1]) {
174 250 throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
175 251 }
176 252 $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
177 - $this->prefixDirsPsr4[$prefix] = (array) $paths;
253 + $this->prefixDirsPsr4[$prefix] = $paths;
178 254 } elseif ($prepend) {
179 255 // Prepend directories for an already registered namespace.
180 256 $this->prefixDirsPsr4[$prefix] = array_merge(
181 - (array) $paths,
257 + $paths,
182 258 $this->prefixDirsPsr4[$prefix]
183 259 );
184 260 } else {
185 261 // Append directories for an already registered namespace.
@@ -184,9 +260,9 @@
184 260 } else {
185 261 // Append directories for an already registered namespace.
186 262 $this->prefixDirsPsr4[$prefix] = array_merge(
187 263 $this->prefixDirsPsr4[$prefix],
188 - (array) $paths
264 + $paths
189 265 );
190 266 }
191 267 }
192 268
@@ -193,10 +269,12 @@
193 269 /**
194 270 * Registers a set of PSR-0 directories for a given prefix,
195 271 * replacing any others previously set for this prefix.
196 272 *
197 - * @param string $prefix The prefix
198 - * @param array|string $paths The PSR-0 base directories
273 + * @param string $prefix The prefix
274 + * @param list<string>|string $paths The PSR-0 base directories
275 + *
276 + * @return void
199 277 */
200 278 public function set($prefix, $paths)
201 279 {
202 280 if (!$prefix) {
@@ -209,12 +287,14 @@
209 287 /**
210 288 * Registers a set of PSR-4 directories for a given namespace,
211 289 * replacing any others previously set for this namespace.
212 290 *
213 - * @param string $prefix The prefix/namespace, with trailing '\\'
214 - * @param array|string $paths The PSR-4 base directories
291 + * @param string $prefix The prefix/namespace, with trailing '\\'
292 + * @param list<string>|string $paths The PSR-4 base directories
215 293 *
216 294 * @throws \InvalidArgumentException
295 + *
296 + * @return void
217 297 */
218 298 public function setPsr4($prefix, $paths)
219 299 {
220 300 if (!$prefix) {
@@ -232,8 +312,10 @@
232 312 /**
233 313 * Turns on searching the include path for class files.
234 314 *
235 315 * @param bool $useIncludePath
316 + *
317 + * @return void
236 318 */
237 319 public function setUseIncludePath($useIncludePath)
238 320 {
239 321 $this->useIncludePath = $useIncludePath;
@@ -254,8 +336,10 @@
254 336 * Turns off searching the prefix and fallback directories for classes
255 337 * that have not been registered with the class map.
256 338 *
257 339 * @param bool $classMapAuthoritative
340 + *
341 + * @return void
258 342 */
259 343 public function setClassMapAuthoritative($classMapAuthoritative)
260 344 {
261 345 $this->classMapAuthoritative = $classMapAuthoritative;
@@ -271,23 +355,64 @@
271 355 return $this->classMapAuthoritative;
272 356 }
273 357
274 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 + /**
275 381 * Registers this instance as an autoloader.
276 382 *
277 383 * @param bool $prepend Whether to prepend the autoloader or not
384 + *
385 + * @return void
278 386 */
279 387 public function register($prepend = false)
280 388 {
281 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 + }
282 401 }
283 402
284 403 /**
285 404 * Unregisters this instance as an autoloader.
405 + *
406 + * @return void
286 407 */
287 408 public function unregister()
288 409 {
289 410 spl_autoload_unregister(array($this, 'loadClass'));
411 +
412 + if (null !== $this->vendorDir) {
413 + unset(self::$registeredLoaders[$this->vendorDir]);
414 + }
290 415 }
291 416
292 417 /**
293 418 * Loads the given class or interface.
@@ -292,17 +417,20 @@
292 417 /**
293 418 * Loads the given class or interface.
294 419 *
295 420 * @param string $class The name of the class
296 - * @return bool|null True if loaded, null otherwise
421 + * @return true|null True if loaded, null otherwise
297 422 */
298 423 public function loadClass($class)
299 424 {
300 425 if ($file = $this->findFile($class)) {
301 - includeFile($file);
426 + $includeFile = self::$includeFile;
427 + $includeFile($file);
302 428
303 429 return true;
304 430 }
431 +
432 + return null;
305 433 }
306 434
307 435 /**
308 436 * Finds the path to the file where the class is defined.
@@ -312,36 +440,56 @@
312 440 * @return string|false The path if found, false otherwise
313 441 */
314 442 public function findFile($class)
315 443 {
316 - // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731
317 - if ('\\' == $class[0]) {
318 - $class = substr($class, 1);
319 - }
320 -
321 444 // class map lookup
322 445 if (isset($this->classMap[$class])) {
323 446 return $this->classMap[$class];
324 447 }
325 - if ($this->classMapAuthoritative) {
448 + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
326 449 return false;
327 450 }
451 + if (null !== $this->apcuPrefix) {
452 + $file = apcu_fetch($this->apcuPrefix.$class, $hit);
453 + if ($hit) {
454 + return $file;
455 + }
456 + }
328 457
329 458 $file = $this->findFileWithExtension($class, '.php');
330 459
331 460 // Search for Hack files if we are running on HHVM
332 - if ($file === null && defined('HHVM_VERSION')) {
461 + if (false === $file && defined('HHVM_VERSION')) {
333 462 $file = $this->findFileWithExtension($class, '.hh');
334 463 }
335 464
336 - if ($file === null) {
465 + if (null !== $this->apcuPrefix) {
466 + apcu_add($this->apcuPrefix.$class, $file);
467 + }
468 +
469 + if (false === $file) {
337 470 // Remember that this class does not exist.
338 - return $this->classMap[$class] = false;
471 + $this->missingClasses[$class] = true;
339 472 }
340 473
341 474 return $file;
342 475 }
343 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 + */
344 492 private function findFileWithExtension($class, $ext)
345 493 {
346 494 // PSR-4 lookup
347 495 $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
@@ -347,12 +495,16 @@
347 495 $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
348 496
349 497 $first = $class[0];
350 498 if (isset($this->prefixLengthsPsr4[$first])) {
351 - foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) {
352 - if (0 === strpos($class, $prefix)) {
353 - foreach ($this->prefixDirsPsr4[$prefix] as $dir) {
354 - if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
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)) {
355 507 return $file;
356 508 }
357 509 }
358 510 }
@@ -398,16 +550,30 @@
398 550 // PSR-0 include paths.
399 551 if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
400 552 return $file;
401 553 }
554 +
555 + return false;
402 556 }
403 -}
404 557
405 -/**
406 - * Scope isolated include.
407 - *
408 - * Prevents access to $this/self from included files.
409 - */
410 -function includeFile($file)
411 -{
412 - include $file;
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 + }
413 579 }