PluginProbe
404 Solution / 4.3.0
404 Solution v4.3.0
4.3.5 4.3.4 4.3.3 4.3.2 4.3.1 4.3.0 4.2.0 4.1.19 4.1.18 4.1.17 4.1.16 4.1.15 4.1.13 4.1.12 4.1.11 4.1.10 4.1.9 4.1.8 4.1.7 4.1.6 4.1.5 4.1.4 4.1.3 trunk 2.30.0 All 109 releases
404-solution / includes / root-boot / Autoloader.php

Autoloader.php in 404 Solution 4.3.0, at includes/root-boot/Autoloader.php

124 lines 4.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if (!defined('ABSPATH')) {
3 exit;
4 }
5
6 /**
7 * Plugin class autoloader.
8 *
9 * Resolves ABJ_404_Solution_* classes via a deterministic classmap
10 * (includes/classmap.php) to avoid runtime glob() scans on real sites. Before
11 * loading a "host" facade class it verifies that the collaborator files it
12 * depends on are present, using the composition-dependency map stored in
13 * includes/data/autoloader-trait-dependencies.php; a missing collaborator is
14 * recorded in $GLOBALS['abj404_missing_files'] and the host class load is
15 * skipped so a corrupt install surfaces a degraded admin page instead of an
16 * uncatchable compile-time fatal.
17 *
18 * The spl_autoload_register() call stays in 404-solution.php (the boot
19 * sequence); this file only defines the function. It is required with a plain
20 * require FIRST in 404-solution.php, before any class use.
21 */
22 // allow-no-test-found: boot-time global function (abj404_autoloader) wired via spl_autoload_register in 404-solution.php; no isolated unit-file seam. The classmap+missing-collaborator resolution behavior is exercised in BootResilienceTest (which references abj404_autoloader directly).
23
24 if (!function_exists('abj404_autoloader')) {
25 /**
26 * @param string $class
27 * @return void
28 */
29 function abj404_autoloader($class) {
30 // some people were having issues with possibly parent classes not being loaded before their children.
31 $childParentMap = [
32 'ABJ_404_Solution_FunctionsMBString' => 'ABJ_404_Solution_Functions',
33 'ABJ_404_Solution_FunctionsPreg' => 'ABJ_404_Solution_Functions',
34 'ABJ_404_Solution_MbStringAdapterMb' => 'ABJ_404_Solution_MbStringAdapter',
35 'ABJ_404_Solution_MbStringAdapterPreg' => 'ABJ_404_Solution_MbStringAdapter',
36 'ABJ_404_Solution_RegexHelperMb' => 'ABJ_404_Solution_RegexHelper',
37 'ABJ_404_Solution_RegexHelperPreg' => 'ABJ_404_Solution_RegexHelper',
38 ];
39
40 // only pay attention if it's for us. don't bother for other things.
41 if (substr($class, 0, 16) !== 'ABJ_404_Solution') {
42 return;
43 }
44
45 // Use a deterministic classmap to avoid runtime glob() scans on real sites.
46 /** @var array<string, string>|null $abj404_autoLoaderClassMap */
47 static $abj404_autoLoaderClassMap = null;
48 if ($abj404_autoLoaderClassMap === null) {
49 $mapFile = dirname(__DIR__) . '/classmap.php';
50 $loadedMap = file_exists($mapFile) ? require $mapFile : array();
51 $normalizedMap = array();
52 if (is_array($loadedMap)) {
53 foreach ($loadedMap as $mappedClass => $mappedFile) {
54 if (is_string($mappedClass) && is_string($mappedFile)) {
55 $normalizedMap[$mappedClass] = $mappedFile;
56 }
57 }
58 }
59 $abj404_autoLoaderClassMap = $normalizedMap;
60 }
61
62 if (!array_key_exists($class, $abj404_autoLoaderClassMap)) {
63 return;
64 }
65
66 // Composition dependency pre-check: parent facade classes depend on files
67 // being present before they are loaded. Verify those files exist first so
68 // a corrupt install can surface a degraded admin page instead of a fatal.
69 // The class->collaborators map is DATA, loaded from an external file.
70 /** @var array<string, array<int, string>>|null $traitDependencies */
71 static $traitDependencies = null;
72 if ($traitDependencies === null) {
73 $mapDataFile = dirname(__DIR__) . '/data/autoloader-trait-dependencies.php';
74 $traitDependencyClasses = file_exists($mapDataFile) ? require $mapDataFile : array();
75 if (!is_array($traitDependencyClasses)) {
76 $traitDependencyClasses = array();
77 }
78 $traitDependencies = array();
79 foreach ($traitDependencyClasses as $hostClass => $dependencyClasses) {
80 $traitDependencies[$hostClass] = array();
81 if (!is_array($dependencyClasses)) {
82 continue;
83 }
84 foreach ($dependencyClasses as $dependencyClass) {
85 if (is_string($dependencyClass) && isset($abj404_autoLoaderClassMap[$dependencyClass])) {
86 $traitDependencies[$hostClass][] = $abj404_autoLoaderClassMap[$dependencyClass];
87 }
88 }
89 }
90 }
91
92 if (isset($traitDependencies[$class])) {
93 foreach ($traitDependencies[$class] as $dependencyFile) {
94 if (!file_exists($dependencyFile)) {
95 abj404_record_missing_file($dependencyFile);
96 // Don't load the parent class: the compile-time fatal is uncatchable.
97 return;
98 }
99 }
100 }
101
102 // Ensure the parent class is loaded first.
103 if (array_key_exists($class, $childParentMap)) {
104 $parentClass = $childParentMap[$class];
105 if (!class_exists($parentClass, false) && array_key_exists($parentClass, $abj404_autoLoaderClassMap)) {
106 $parentFile = $abj404_autoLoaderClassMap[$parentClass];
107 if (!file_exists($parentFile)) {
108 abj404_record_missing_file($parentFile);
109 return;
110 }
111 require_once $parentFile;
112 }
113 }
114
115 $classFile = $abj404_autoLoaderClassMap[$class];
116 if (!file_exists($classFile)) {
117 abj404_record_missing_file($classFile);
118 return;
119 }
120
121 require_once $classFile;
122 }
123 }
124