Mercurial > hg > isophonics-drupal-site
comparison vendor/symfony/debug/DebugClassLoader.php @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children | 7a779792577d |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4c8ae668cc8c |
---|---|
1 <?php | |
2 | |
3 /* | |
4 * This file is part of the Symfony package. | |
5 * | |
6 * (c) Fabien Potencier <fabien@symfony.com> | |
7 * | |
8 * For the full copyright and license information, please view the LICENSE | |
9 * file that was distributed with this source code. | |
10 */ | |
11 | |
12 namespace Symfony\Component\Debug; | |
13 | |
14 /** | |
15 * Autoloader checking if the class is really defined in the file found. | |
16 * | |
17 * The ClassLoader will wrap all registered autoloaders | |
18 * and will throw an exception if a file is found but does | |
19 * not declare the class. | |
20 * | |
21 * @author Fabien Potencier <fabien@symfony.com> | |
22 * @author Christophe Coevoet <stof@notk.org> | |
23 * @author Nicolas Grekas <p@tchwork.com> | |
24 */ | |
25 class DebugClassLoader | |
26 { | |
27 private $classLoader; | |
28 private $isFinder; | |
29 private static $caseCheck; | |
30 private static $deprecated = array(); | |
31 private static $php7Reserved = array('int', 'float', 'bool', 'string', 'true', 'false', 'null'); | |
32 private static $darwinCache = array('/' => array('/', array())); | |
33 | |
34 /** | |
35 * Constructor. | |
36 * | |
37 * @param callable $classLoader A class loader | |
38 */ | |
39 public function __construct(callable $classLoader) | |
40 { | |
41 $this->classLoader = $classLoader; | |
42 $this->isFinder = is_array($classLoader) && method_exists($classLoader[0], 'findFile'); | |
43 | |
44 if (!isset(self::$caseCheck)) { | |
45 $file = file_exists(__FILE__) ? __FILE__ : rtrim(realpath('.'), DIRECTORY_SEPARATOR); | |
46 $i = strrpos($file, DIRECTORY_SEPARATOR); | |
47 $dir = substr($file, 0, 1 + $i); | |
48 $file = substr($file, 1 + $i); | |
49 $test = strtoupper($file) === $file ? strtolower($file) : strtoupper($file); | |
50 $test = realpath($dir.$test); | |
51 | |
52 if (false === $test || false === $i) { | |
53 // filesystem is case sensitive | |
54 self::$caseCheck = 0; | |
55 } elseif (substr($test, -strlen($file)) === $file) { | |
56 // filesystem is case insensitive and realpath() normalizes the case of characters | |
57 self::$caseCheck = 1; | |
58 } elseif (false !== stripos(PHP_OS, 'darwin')) { | |
59 // on MacOSX, HFS+ is case insensitive but realpath() doesn't normalize the case of characters | |
60 self::$caseCheck = 2; | |
61 } else { | |
62 // filesystem case checks failed, fallback to disabling them | |
63 self::$caseCheck = 0; | |
64 } | |
65 } | |
66 } | |
67 | |
68 /** | |
69 * Gets the wrapped class loader. | |
70 * | |
71 * @return callable The wrapped class loader | |
72 */ | |
73 public function getClassLoader() | |
74 { | |
75 return $this->classLoader; | |
76 } | |
77 | |
78 /** | |
79 * Wraps all autoloaders. | |
80 */ | |
81 public static function enable() | |
82 { | |
83 // Ensures we don't hit https://bugs.php.net/42098 | |
84 class_exists('Symfony\Component\Debug\ErrorHandler'); | |
85 class_exists('Psr\Log\LogLevel'); | |
86 | |
87 if (!is_array($functions = spl_autoload_functions())) { | |
88 return; | |
89 } | |
90 | |
91 foreach ($functions as $function) { | |
92 spl_autoload_unregister($function); | |
93 } | |
94 | |
95 foreach ($functions as $function) { | |
96 if (!is_array($function) || !$function[0] instanceof self) { | |
97 $function = array(new static($function), 'loadClass'); | |
98 } | |
99 | |
100 spl_autoload_register($function); | |
101 } | |
102 } | |
103 | |
104 /** | |
105 * Disables the wrapping. | |
106 */ | |
107 public static function disable() | |
108 { | |
109 if (!is_array($functions = spl_autoload_functions())) { | |
110 return; | |
111 } | |
112 | |
113 foreach ($functions as $function) { | |
114 spl_autoload_unregister($function); | |
115 } | |
116 | |
117 foreach ($functions as $function) { | |
118 if (is_array($function) && $function[0] instanceof self) { | |
119 $function = $function[0]->getClassLoader(); | |
120 } | |
121 | |
122 spl_autoload_register($function); | |
123 } | |
124 } | |
125 | |
126 /** | |
127 * Loads the given class or interface. | |
128 * | |
129 * @param string $class The name of the class | |
130 * | |
131 * @return bool|null True, if loaded | |
132 * | |
133 * @throws \RuntimeException | |
134 */ | |
135 public function loadClass($class) | |
136 { | |
137 ErrorHandler::stackErrors(); | |
138 | |
139 try { | |
140 if ($this->isFinder) { | |
141 if ($file = $this->classLoader[0]->findFile($class)) { | |
142 require_once $file; | |
143 } | |
144 } else { | |
145 call_user_func($this->classLoader, $class); | |
146 $file = false; | |
147 } | |
148 } finally { | |
149 ErrorHandler::unstackErrors(); | |
150 } | |
151 | |
152 $exists = class_exists($class, false) || interface_exists($class, false) || trait_exists($class, false); | |
153 | |
154 if ($class && '\\' === $class[0]) { | |
155 $class = substr($class, 1); | |
156 } | |
157 | |
158 if ($exists) { | |
159 $refl = new \ReflectionClass($class); | |
160 $name = $refl->getName(); | |
161 | |
162 if ($name !== $class && 0 === strcasecmp($name, $class)) { | |
163 throw new \RuntimeException(sprintf('Case mismatch between loaded and declared class names: %s vs %s', $class, $name)); | |
164 } | |
165 | |
166 if (in_array(strtolower($refl->getShortName()), self::$php7Reserved)) { | |
167 @trigger_error(sprintf('%s uses a reserved class name (%s) that will break on PHP 7 and higher', $name, $refl->getShortName()), E_USER_DEPRECATED); | |
168 } elseif (preg_match('#\n \* @deprecated (.*?)\r?\n \*(?: @|/$)#s', $refl->getDocComment(), $notice)) { | |
169 self::$deprecated[$name] = preg_replace('#\s*\r?\n \* +#', ' ', $notice[1]); | |
170 } else { | |
171 if (2 > $len = 1 + (strpos($name, '\\', 1 + strpos($name, '\\')) ?: strpos($name, '_'))) { | |
172 $len = 0; | |
173 $ns = ''; | |
174 } else { | |
175 switch ($ns = substr($name, 0, $len)) { | |
176 case 'Symfony\Bridge\\': | |
177 case 'Symfony\Bundle\\': | |
178 case 'Symfony\Component\\': | |
179 $ns = 'Symfony\\'; | |
180 $len = strlen($ns); | |
181 break; | |
182 } | |
183 } | |
184 $parent = get_parent_class($class); | |
185 | |
186 if (!$parent || strncmp($ns, $parent, $len)) { | |
187 if ($parent && isset(self::$deprecated[$parent]) && strncmp($ns, $parent, $len)) { | |
188 @trigger_error(sprintf('The %s class extends %s that is deprecated %s', $name, $parent, self::$deprecated[$parent]), E_USER_DEPRECATED); | |
189 } | |
190 | |
191 $parentInterfaces = array(); | |
192 $deprecatedInterfaces = array(); | |
193 if ($parent) { | |
194 foreach (class_implements($parent) as $interface) { | |
195 $parentInterfaces[$interface] = 1; | |
196 } | |
197 } | |
198 | |
199 foreach ($refl->getInterfaceNames() as $interface) { | |
200 if (isset(self::$deprecated[$interface]) && strncmp($ns, $interface, $len)) { | |
201 $deprecatedInterfaces[] = $interface; | |
202 } | |
203 foreach (class_implements($interface) as $interface) { | |
204 $parentInterfaces[$interface] = 1; | |
205 } | |
206 } | |
207 | |
208 foreach ($deprecatedInterfaces as $interface) { | |
209 if (!isset($parentInterfaces[$interface])) { | |
210 @trigger_error(sprintf('The %s %s %s that is deprecated %s', $name, $refl->isInterface() ? 'interface extends' : 'class implements', $interface, self::$deprecated[$interface]), E_USER_DEPRECATED); | |
211 } | |
212 } | |
213 } | |
214 } | |
215 } | |
216 | |
217 if ($file) { | |
218 if (!$exists) { | |
219 if (false !== strpos($class, '/')) { | |
220 throw new \RuntimeException(sprintf('Trying to autoload a class with an invalid name "%s". Be careful that the namespace separator is "\" in PHP, not "/".', $class)); | |
221 } | |
222 | |
223 throw new \RuntimeException(sprintf('The autoloader expected class "%s" to be defined in file "%s". The file was found but the class was not in it, the class name or namespace probably has a typo.', $class, $file)); | |
224 } | |
225 if (self::$caseCheck) { | |
226 $real = explode('\\', $class.strrchr($file, '.')); | |
227 $tail = explode(DIRECTORY_SEPARATOR, str_replace('/', DIRECTORY_SEPARATOR, $file)); | |
228 | |
229 $i = count($tail) - 1; | |
230 $j = count($real) - 1; | |
231 | |
232 while (isset($tail[$i], $real[$j]) && $tail[$i] === $real[$j]) { | |
233 --$i; | |
234 --$j; | |
235 } | |
236 | |
237 array_splice($tail, 0, $i + 1); | |
238 } | |
239 if (self::$caseCheck && $tail) { | |
240 $tail = DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR, $tail); | |
241 $tailLen = strlen($tail); | |
242 $real = $refl->getFileName(); | |
243 | |
244 if (2 === self::$caseCheck) { | |
245 // realpath() on MacOSX doesn't normalize the case of characters | |
246 | |
247 $i = 1 + strrpos($real, '/'); | |
248 $file = substr($real, $i); | |
249 $real = substr($real, 0, $i); | |
250 | |
251 if (isset(self::$darwinCache[$real])) { | |
252 $kDir = $real; | |
253 } else { | |
254 $kDir = strtolower($real); | |
255 | |
256 if (isset(self::$darwinCache[$kDir])) { | |
257 $real = self::$darwinCache[$kDir][0]; | |
258 } else { | |
259 $dir = getcwd(); | |
260 chdir($real); | |
261 $real = getcwd().'/'; | |
262 chdir($dir); | |
263 | |
264 $dir = $real; | |
265 $k = $kDir; | |
266 $i = strlen($dir) - 1; | |
267 while (!isset(self::$darwinCache[$k])) { | |
268 self::$darwinCache[$k] = array($dir, array()); | |
269 self::$darwinCache[$dir] = &self::$darwinCache[$k]; | |
270 | |
271 while ('/' !== $dir[--$i]) { | |
272 } | |
273 $k = substr($k, 0, ++$i); | |
274 $dir = substr($dir, 0, $i--); | |
275 } | |
276 } | |
277 } | |
278 | |
279 $dirFiles = self::$darwinCache[$kDir][1]; | |
280 | |
281 if (isset($dirFiles[$file])) { | |
282 $kFile = $file; | |
283 } else { | |
284 $kFile = strtolower($file); | |
285 | |
286 if (!isset($dirFiles[$kFile])) { | |
287 foreach (scandir($real, 2) as $f) { | |
288 if ('.' !== $f[0]) { | |
289 $dirFiles[$f] = $f; | |
290 if ($f === $file) { | |
291 $kFile = $k = $file; | |
292 } elseif ($f !== $k = strtolower($f)) { | |
293 $dirFiles[$k] = $f; | |
294 } | |
295 } | |
296 } | |
297 self::$darwinCache[$kDir][1] = $dirFiles; | |
298 } | |
299 } | |
300 | |
301 $real .= $dirFiles[$kFile]; | |
302 } | |
303 | |
304 if (0 === substr_compare($real, $tail, -$tailLen, $tailLen, true) | |
305 && 0 !== substr_compare($real, $tail, -$tailLen, $tailLen, false) | |
306 ) { | |
307 throw new \RuntimeException(sprintf('Case mismatch between class and real file names: %s vs %s in %s', substr($tail, -$tailLen + 1), substr($real, -$tailLen + 1), substr($real, 0, -$tailLen + 1))); | |
308 } | |
309 } | |
310 | |
311 return true; | |
312 } | |
313 } | |
314 } |