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