Verzeichnisstruktur phpBB-3.2.0
- Veröffentlicht
- 06.01.2017
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 Symfony\Component\Debug\Exception\ClassNotFoundException;
015 use Symfony\Component\Debug\Exception\FatalErrorException;
016 use Symfony\Component\Debug\DebugClassLoader;
017 use Composer\Autoload\ClassLoader as ComposerClassLoader;
018 use Symfony\Component\ClassLoader\ClassLoader as SymfonyClassLoader;
019 use Symfony\Component\ClassLoader\UniversalClassLoader as SymfonyUniversalClassLoader;
020
021 /**
022 * ErrorHandler for classes that do not exist.
023 *
024 * @author Fabien Potencier <fabien@symfony.com>
025 */
026 class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
027 {
028 /**
029 * {@inheritdoc}
030 */
031 public function handleError(array $error, FatalErrorException $exception)
032 {
033 $messageLen = strlen($error['message']);
034 $notFoundSuffix = '\' not found';
035 $notFoundSuffixLen = strlen($notFoundSuffix);
036 if ($notFoundSuffixLen > $messageLen) {
037 return;
038 }
039
040 if (0 !== substr_compare($error['message'], $notFoundSuffix, -$notFoundSuffixLen)) {
041 return;
042 }
043
044 foreach (array('class', 'interface', 'trait') as $typeName) {
045 $prefix = ucfirst($typeName).' \'';
046 $prefixLen = strlen($prefix);
047 if (0 !== strpos($error['message'], $prefix)) {
048 continue;
049 }
050
051 $fullyQualifiedClassName = substr($error['message'], $prefixLen, -$notFoundSuffixLen);
052 if (false !== $namespaceSeparatorIndex = strrpos($fullyQualifiedClassName, '\\')) {
053 $className = substr($fullyQualifiedClassName, $namespaceSeparatorIndex + 1);
054 $namespacePrefix = substr($fullyQualifiedClassName, 0, $namespaceSeparatorIndex);
055 $message = sprintf('Attempted to load %s "%s" from namespace "%s".', $typeName, $className, $namespacePrefix);
056 $tail = ' for another namespace?';
057 } else {
058 $className = $fullyQualifiedClassName;
059 $message = sprintf('Attempted to load %s "%s" from the global namespace.', $typeName, $className);
060 $tail = '?';
061 }
062
063 if ($candidates = $this->getClassCandidates($className)) {
064 $tail = array_pop($candidates).'"?';
065 if ($candidates) {
066 $tail = ' for e.g. "'.implode('", "', $candidates).'" or "'.$tail;
067 } else {
068 $tail = ' for "'.$tail;
069 }
070 }
071 $message .= "\nDid you forget a \"use\" statement".$tail;
072
073 return new ClassNotFoundException($message, $exception);
074 }
075 }
076
077 /**
078 * Tries to guess the full namespace for a given class name.
079 *
080 * By default, it looks for PSR-0 and PSR-4 classes registered via a Symfony or a Composer
081 * autoloader (that should cover all common cases).
082 *
083 * @param string $class A class name (without its namespace)
084 *
085 * @return array An array of possible fully qualified class names
086 */
087 private function getClassCandidates($class)
088 {
089 if (!is_array($functions = spl_autoload_functions())) {
090 return array();
091 }
092
093 // find Symfony and Composer autoloaders
094 $classes = array();
095
096 foreach ($functions as $function) {
097 if (!is_array($function)) {
098 continue;
099 }
100 // get class loaders wrapped by DebugClassLoader
101 if ($function[0] instanceof DebugClassLoader) {
102 $function = $function[0]->getClassLoader();
103
104 // @deprecated since version 2.5. Returning an object from DebugClassLoader::getClassLoader() is deprecated.
105 if (is_object($function)) {
106 $function = array($function);
107 }
108
109 if (!is_array($function)) {
110 continue;
111 }
112 }
113
114 if ($function[0] instanceof ComposerClassLoader || $function[0] instanceof SymfonyClassLoader || $function[0] instanceof SymfonyUniversalClassLoader) {
115 foreach ($function[0]->getPrefixes() as $prefix => $paths) {
116 foreach ($paths as $path) {
117 $classes = array_merge($classes, $this->findClassInPath($path, $class, $prefix));
118 }
119 }
120 }
121 if ($function[0] instanceof ComposerClassLoader) {
122 foreach ($function[0]->getPrefixesPsr4() as $prefix => $paths) {
123 foreach ($paths as $path) {
124 $classes = array_merge($classes, $this->findClassInPath($path, $class, $prefix));
125 }
126 }
127 }
128 }
129
130 return array_unique($classes);
131 }
132
133 /**
134 * @param string $path
135 * @param string $class
136 * @param string $prefix
137 *
138 * @return array
139 */
140 private function findClassInPath($path, $class, $prefix)
141 {
142 if (!$path = realpath($path.'/'.strtr($prefix, '\\_', '//')) ?: realpath($path.'/'.dirname(strtr($prefix, '\\_', '//'))) ?: realpath($path)) {
143 return array();
144 }
145
146 $classes = array();
147 $filename = $class.'.php';
148 foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
149 if ($filename == $file->getFileName() && $class = $this->convertFileToClass($path, $file->getPathName(), $prefix)) {
150 $classes[] = $class;
151 }
152 }
153
154 return $classes;
155 }
156
157 /**
158 * @param string $path
159 * @param string $file
160 * @param string $prefix
161 *
162 * @return string|null
163 */
164 private function convertFileToClass($path, $file, $prefix)
165 {
166 $candidates = array(
167 // namespaced class
168 $namespacedClass = str_replace(array($path.DIRECTORY_SEPARATOR, '.php', '/'), array('', '', '\\'), $file),
169 // namespaced class (with target dir)
170 $prefix.$namespacedClass,
171 // namespaced class (with target dir and separator)
172 $prefix.'\\'.$namespacedClass,
173 // PEAR class
174 str_replace('\\', '_', $namespacedClass),
175 // PEAR class (with target dir)
176 str_replace('\\', '_', $prefix.$namespacedClass),
177 // PEAR class (with target dir and separator)
178 str_replace('\\', '_', $prefix.'\\'.$namespacedClass),
179 );
180
181 if ($prefix) {
182 $candidates = array_filter($candidates, function ($candidate) use ($prefix) {return 0 === strpos($candidate, $prefix);});
183 }
184
185 // We cannot use the autoloader here as most of them use require; but if the class
186 // is not found, the new autoloader call will require the file again leading to a
187 // "cannot redeclare class" error.
188 foreach ($candidates as $candidate) {
189 if ($this->classExists($candidate)) {
190 return $candidate;
191 }
192 }
193
194 require_once $file;
195
196 foreach ($candidates as $candidate) {
197 if ($this->classExists($candidate)) {
198 return $candidate;
199 }
200 }
201 }
202
203 /**
204 * @param string $class
205 *
206 * @return bool
207 */
208 private function classExists($class)
209 {
210 return class_exists($class, false) || interface_exists($class, false) || (function_exists('trait_exists') && trait_exists($class, false));
211 }
212 }
213