class ClassNotFoundFatalErrorHandler in Zircon Profile 8
Same name and namespace in other branches
- 8.0 vendor/symfony/debug/FatalErrorHandler/ClassNotFoundFatalErrorHandler.php \Symfony\Component\Debug\FatalErrorHandler\ClassNotFoundFatalErrorHandler
ErrorHandler for classes that do not exist.
@author Fabien Potencier <fabien@symfony.com>
Hierarchy
- class \Symfony\Component\Debug\FatalErrorHandler\ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
Expanded class hierarchy of ClassNotFoundFatalErrorHandler
2 files declare their use of ClassNotFoundFatalErrorHandler
- ClassNotFoundFatalErrorHandlerTest.php in vendor/
symfony/ debug/ Tests/ FatalErrorHandler/ ClassNotFoundFatalErrorHandlerTest.php - ErrorHandler.php in vendor/
symfony/ debug/ ErrorHandler.php
File
- vendor/
symfony/ debug/ FatalErrorHandler/ ClassNotFoundFatalErrorHandler.php, line 26
Namespace
Symfony\Component\Debug\FatalErrorHandlerView source
class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface {
/**
* {@inheritdoc}
*/
public function handleError(array $error, FatalErrorException $exception) {
$messageLen = strlen($error['message']);
$notFoundSuffix = '\' not found';
$notFoundSuffixLen = strlen($notFoundSuffix);
if ($notFoundSuffixLen > $messageLen) {
return;
}
if (0 !== substr_compare($error['message'], $notFoundSuffix, -$notFoundSuffixLen)) {
return;
}
foreach (array(
'class',
'interface',
'trait',
) as $typeName) {
$prefix = ucfirst($typeName) . ' \'';
$prefixLen = strlen($prefix);
if (0 !== strpos($error['message'], $prefix)) {
continue;
}
$fullyQualifiedClassName = substr($error['message'], $prefixLen, -$notFoundSuffixLen);
if (false !== ($namespaceSeparatorIndex = strrpos($fullyQualifiedClassName, '\\'))) {
$className = substr($fullyQualifiedClassName, $namespaceSeparatorIndex + 1);
$namespacePrefix = substr($fullyQualifiedClassName, 0, $namespaceSeparatorIndex);
$message = sprintf('Attempted to load %s "%s" from namespace "%s".', $typeName, $className, $namespacePrefix);
$tail = ' for another namespace?';
}
else {
$className = $fullyQualifiedClassName;
$message = sprintf('Attempted to load %s "%s" from the global namespace.', $typeName, $className);
$tail = '?';
}
if ($candidates = $this
->getClassCandidates($className)) {
$tail = array_pop($candidates) . '"?';
if ($candidates) {
$tail = ' for e.g. "' . implode('", "', $candidates) . '" or "' . $tail;
}
else {
$tail = ' for "' . $tail;
}
}
$message .= "\nDid you forget a \"use\" statement" . $tail;
return new ClassNotFoundException($message, $exception);
}
}
/**
* Tries to guess the full namespace for a given class name.
*
* By default, it looks for PSR-0 and PSR-4 classes registered via a Symfony or a Composer
* autoloader (that should cover all common cases).
*
* @param string $class A class name (without its namespace)
*
* @return array An array of possible fully qualified class names
*/
private function getClassCandidates($class) {
if (!is_array($functions = spl_autoload_functions())) {
return array();
}
// find Symfony and Composer autoloaders
$classes = array();
foreach ($functions as $function) {
if (!is_array($function)) {
continue;
}
// get class loaders wrapped by DebugClassLoader
if ($function[0] instanceof DebugClassLoader) {
$function = $function[0]
->getClassLoader();
// @deprecated since version 2.5. Returning an object from DebugClassLoader::getClassLoader() is deprecated.
if (is_object($function)) {
$function = array(
$function,
);
}
if (!is_array($function)) {
continue;
}
}
if ($function[0] instanceof ComposerClassLoader || $function[0] instanceof SymfonyClassLoader || $function[0] instanceof SymfonyUniversalClassLoader) {
foreach ($function[0]
->getPrefixes() as $prefix => $paths) {
foreach ($paths as $path) {
$classes = array_merge($classes, $this
->findClassInPath($path, $class, $prefix));
}
}
}
if ($function[0] instanceof ComposerClassLoader) {
foreach ($function[0]
->getPrefixesPsr4() as $prefix => $paths) {
foreach ($paths as $path) {
$classes = array_merge($classes, $this
->findClassInPath($path, $class, $prefix));
}
}
}
}
return array_unique($classes);
}
/**
* @param string $path
* @param string $class
* @param string $prefix
*
* @return array
*/
private function findClassInPath($path, $class, $prefix) {
if (!($path = realpath($path . '/' . strtr($prefix, '\\_', '//')) ?: realpath($path . '/' . dirname(strtr($prefix, '\\_', '//'))) ?: realpath($path))) {
return array();
}
$classes = array();
$filename = $class . '.php';
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
if ($filename == $file
->getFileName() && ($class = $this
->convertFileToClass($path, $file
->getPathName(), $prefix))) {
$classes[] = $class;
}
}
return $classes;
}
/**
* @param string $path
* @param string $file
* @param string $prefix
*
* @return string|null
*/
private function convertFileToClass($path, $file, $prefix) {
$candidates = array(
// namespaced class
$namespacedClass = str_replace(array(
$path . DIRECTORY_SEPARATOR,
'.php',
'/',
), array(
'',
'',
'\\',
), $file),
// namespaced class (with target dir)
$prefix . $namespacedClass,
// namespaced class (with target dir and separator)
$prefix . '\\' . $namespacedClass,
// PEAR class
str_replace('\\', '_', $namespacedClass),
// PEAR class (with target dir)
str_replace('\\', '_', $prefix . $namespacedClass),
// PEAR class (with target dir and separator)
str_replace('\\', '_', $prefix . '\\' . $namespacedClass),
);
if ($prefix) {
$candidates = array_filter($candidates, function ($candidate) use ($prefix) {
return 0 === strpos($candidate, $prefix);
});
}
// We cannot use the autoloader here as most of them use require; but if the class
// is not found, the new autoloader call will require the file again leading to a
// "cannot redeclare class" error.
foreach ($candidates as $candidate) {
if ($this
->classExists($candidate)) {
return $candidate;
}
}
require_once $file;
foreach ($candidates as $candidate) {
if ($this
->classExists($candidate)) {
return $candidate;
}
}
}
/**
* @param string $class
*
* @return bool
*/
private function classExists($class) {
return class_exists($class, false) || interface_exists($class, false) || function_exists('trait_exists') && trait_exists($class, false);
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
ClassNotFoundFatalErrorHandler:: |
private | function | ||
ClassNotFoundFatalErrorHandler:: |
private | function | ||
ClassNotFoundFatalErrorHandler:: |
private | function | ||
ClassNotFoundFatalErrorHandler:: |
private | function | Tries to guess the full namespace for a given class name. | |
ClassNotFoundFatalErrorHandler:: |
public | function |
Attempts to convert an error into an exception. Overrides FatalErrorHandlerInterface:: |