Verzeichnisstruktur phpBB-3.3.15
- Veröffentlicht
- 28.08.2024
So funktioniert es
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
ClassNotFoundFatalErrorHandler.php
001 <?php
002
003 /*
004 * This file is part of the Symfony package.
005 *
006 * (c) Fabien Potencier <fabien@symfony.com>
007 *
008 * For the full copyright and license information, please view the LICENSE
009 * file that was distributed with this source code.
010 */
011
012 namespace Symfony\Component\Debug\FatalErrorHandler;
013
014 use Composer\Autoload\ClassLoader as ComposerClassLoader;
015 use Symfony\Component\ClassLoader\ClassLoader as SymfonyClassLoader;
016 use Symfony\Component\Debug\DebugClassLoader;
017 use Symfony\Component\Debug\Exception\ClassNotFoundException;
018 use Symfony\Component\Debug\Exception\FatalErrorException;
019
020 /**
021 * ErrorHandler for classes that do not exist.
022 *
023 * @author Fabien Potencier <fabien@symfony.com>
024 */
025 class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
026 {
027 /**
028 * {@inheritdoc}
029 */
030 public function handleError(array $error, FatalErrorException $exception)
031 {
032 if (!preg_match('/^(Class|Interface|Trait) [\'"]([^\'"]+)[\'"] not found$/', $error['message'], $matches)) {
033 return null;
034 }
035 $typeName = strtolower($matches[1]);
036 $fullyQualifiedClassName = $matches[2];
037
038 if (false !== $namespaceSeparatorIndex = strrpos($fullyQualifiedClassName, '\\')) {
039 $className = substr($fullyQualifiedClassName, $namespaceSeparatorIndex + 1);
040 $namespacePrefix = substr($fullyQualifiedClassName, 0, $namespaceSeparatorIndex);
041 $message = sprintf('Attempted to load %s "%s" from namespace "%s".', $typeName, $className, $namespacePrefix);
042 $tail = ' for another namespace?';
043 } else {
044 $className = $fullyQualifiedClassName;
045 $message = sprintf('Attempted to load %s "%s" from the global namespace.', $typeName, $className);
046 $tail = '?';
047 }
048
049 if ($candidates = $this->getClassCandidates($className)) {
050 $tail = array_pop($candidates).'"?';
051 if ($candidates) {
052 $tail = ' for e.g. "'.implode('", "', $candidates).'" or "'.$tail;
053 } else {
054 $tail = ' for "'.$tail;
055 }
056 }
057 $message .= "\nDid you forget a \"use\" statement".$tail;
058
059 return new ClassNotFoundException($message, $exception);
060 }
061
062 /**
063 * Tries to guess the full namespace for a given class name.
064 *
065 * By default, it looks for PSR-0 and PSR-4 classes registered via a Symfony or a Composer
066 * autoloader (that should cover all common cases).
067 *
068 * @param string $class A class name (without its namespace)
069 *
070 * @return array An array of possible fully qualified class names
071 */
072 private function getClassCandidates($class)
073 {
074 if (!\is_array($functions = spl_autoload_functions())) {
075 return [];
076 }
077
078 // find Symfony and Composer autoloaders
079 $classes = [];
080
081 foreach ($functions as $function) {
082 if (!\is_array($function)) {
083 continue;
084 }
085 // get class loaders wrapped by DebugClassLoader
086 if ($function[0] instanceof DebugClassLoader) {
087 $function = $function[0]->getClassLoader();
088
089 if (!\is_array($function)) {
090 continue;
091 }
092 }
093
094 if ($function[0] instanceof ComposerClassLoader || $function[0] instanceof SymfonyClassLoader) {
095 foreach ($function[0]->getPrefixes() as $prefix => $paths) {
096 foreach ($paths as $path) {
097 $classes = array_merge($classes, $this->findClassInPath($path, $class, $prefix));
098 }
099 }
100 }
101 if ($function[0] instanceof ComposerClassLoader) {
102 foreach ($function[0]->getPrefixesPsr4() as $prefix => $paths) {
103 foreach ($paths as $path) {
104 $classes = array_merge($classes, $this->findClassInPath($path, $class, $prefix));
105 }
106 }
107 }
108 }
109
110 return array_unique($classes);
111 }
112
113 /**
114 * @param string $path
115 * @param string $class
116 * @param string $prefix
117 *
118 * @return array
119 */
120 private function findClassInPath($path, $class, $prefix)
121 {
122 if (!$path = realpath($path.'/'.strtr($prefix, '\\_', '//')) ?: realpath($path.'/'.\dirname(strtr($prefix, '\\_', '//'))) ?: realpath($path)) {
123 return [];
124 }
125
126 $classes = [];
127 $filename = $class.'.php';
128 foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
129 if ($filename == $file->getFileName() && $class = $this->convertFileToClass($path, $file->getPathName(), $prefix)) {
130 $classes[] = $class;
131 }
132 }
133
134 return $classes;
135 }
136
137 /**
138 * @param string $path
139 * @param string $file
140 * @param string $prefix
141 *
142 * @return string|null
143 */
144 private function convertFileToClass($path, $file, $prefix)
145 {
146 $candidates = [
147 // namespaced class
148 $namespacedClass = str_replace([$path.\DIRECTORY_SEPARATOR, '.php', '/'], ['', '', '\\'], $file),
149 // namespaced class (with target dir)
150 $prefix.$namespacedClass,
151 // namespaced class (with target dir and separator)
152 $prefix.'\\'.$namespacedClass,
153 // PEAR class
154 str_replace('\\', '_', $namespacedClass),
155 // PEAR class (with target dir)
156 str_replace('\\', '_', $prefix.$namespacedClass),
157 // PEAR class (with target dir and separator)
158 str_replace('\\', '_', $prefix.'\\'.$namespacedClass),
159 ];
160
161 if ($prefix) {
162 $candidates = array_filter($candidates, function ($candidate) use ($prefix) { return 0 === strpos($candidate, $prefix); });
163 }
164
165 // We cannot use the autoloader here as most of them use require; but if the class
166 // is not found, the new autoloader call will require the file again leading to a
167 // "cannot redeclare class" error.
168 foreach ($candidates as $candidate) {
169 if ($this->classExists($candidate)) {
170 return $candidate;
171 }
172 }
173
174 try {
175 require_once $file;
176 } catch (\Throwable $e) {
177 return null;
178 }
179
180 foreach ($candidates as $candidate) {
181 if ($this->classExists($candidate)) {
182 return $candidate;
183 }
184 }
185
186 return null;
187 }
188
189 /**
190 * @param string $class
191 *
192 * @return bool
193 */
194 private function classExists($class)
195 {
196 return class_exists($class, false) || interface_exists($class, false) || trait_exists($class, false);
197 }
198 }
199