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.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

ClassNotFoundFatalErrorHandler.php

Zuletzt modifiziert: 02.04.2025, 15:03 - Dateigröße: 6.74 KiB


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