[ Index ]

PHP Cross Reference of phpBB-3.2.11-deutsch

title

Body

[close]

/vendor/symfony/debug/FatalErrorHandler/ -> ClassNotFoundFatalErrorHandler.php (source)

   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  }


Generated: Wed Nov 11 20:33:01 2020 Cross-referenced by PHPXref 0.7.1