[ Index ] |
PHP Cross Reference of phpBB-3.2.11-deutsch |
[Summary view] [Print] [Text view]
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\FatalErrorHandler; 13 14 use Composer\Autoload\ClassLoader as ComposerClassLoader; 15 use Symfony\Component\ClassLoader\ClassLoader as SymfonyClassLoader; 16 use Symfony\Component\ClassLoader\UniversalClassLoader as SymfonyUniversalClassLoader; 17 use Symfony\Component\Debug\DebugClassLoader; 18 use Symfony\Component\Debug\Exception\ClassNotFoundException; 19 use Symfony\Component\Debug\Exception\FatalErrorException; 20 21 /** 22 * ErrorHandler for classes that do not exist. 23 * 24 * @author Fabien Potencier <fabien@symfony.com> 25 */ 26 class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface 27 { 28 /** 29 * {@inheritdoc} 30 */ 31 public function handleError(array $error, FatalErrorException $exception) 32 { 33 $messageLen = \strlen($error['message']); 34 $notFoundSuffix = '\' not found'; 35 $notFoundSuffixLen = \strlen($notFoundSuffix); 36 if ($notFoundSuffixLen > $messageLen) { 37 return; 38 } 39 40 if (0 !== substr_compare($error['message'], $notFoundSuffix, -$notFoundSuffixLen)) { 41 return; 42 } 43 44 foreach (array('class', 'interface', 'trait') as $typeName) { 45 $prefix = ucfirst($typeName).' \''; 46 $prefixLen = \strlen($prefix); 47 if (0 !== strpos($error['message'], $prefix)) { 48 continue; 49 } 50 51 $fullyQualifiedClassName = substr($error['message'], $prefixLen, -$notFoundSuffixLen); 52 if (false !== $namespaceSeparatorIndex = strrpos($fullyQualifiedClassName, '\\')) { 53 $className = substr($fullyQualifiedClassName, $namespaceSeparatorIndex + 1); 54 $namespacePrefix = substr($fullyQualifiedClassName, 0, $namespaceSeparatorIndex); 55 $message = sprintf('Attempted to load %s "%s" from namespace "%s".', $typeName, $className, $namespacePrefix); 56 $tail = ' for another namespace?'; 57 } else { 58 $className = $fullyQualifiedClassName; 59 $message = sprintf('Attempted to load %s "%s" from the global namespace.', $typeName, $className); 60 $tail = '?'; 61 } 62 63 if ($candidates = $this->getClassCandidates($className)) { 64 $tail = array_pop($candidates).'"?'; 65 if ($candidates) { 66 $tail = ' for e.g. "'.implode('", "', $candidates).'" or "'.$tail; 67 } else { 68 $tail = ' for "'.$tail; 69 } 70 } 71 $message .= "\nDid you forget a \"use\" statement".$tail; 72 73 return new ClassNotFoundException($message, $exception); 74 } 75 } 76 77 /** 78 * Tries to guess the full namespace for a given class name. 79 * 80 * By default, it looks for PSR-0 and PSR-4 classes registered via a Symfony or a Composer 81 * autoloader (that should cover all common cases). 82 * 83 * @param string $class A class name (without its namespace) 84 * 85 * @return array An array of possible fully qualified class names 86 */ 87 private function getClassCandidates($class) 88 { 89 if (!\is_array($functions = spl_autoload_functions())) { 90 return array(); 91 } 92 93 // find Symfony and Composer autoloaders 94 $classes = array(); 95 96 foreach ($functions as $function) { 97 if (!\is_array($function)) { 98 continue; 99 } 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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Nov 11 20:33:01 2020 | Cross-referenced by PHPXref 0.7.1 |