bug #38049 [Debug] Parse "x not found" errors correctly on php 8 (derrabus)
This PR was merged into the 3.4 branch.
Discussion
----------
[Debug] Parse "x not found" errors correctly on php 8
| Q | A
| ------------- | ---
| Branch? | 3.4
| Bug fix? | yes
| New feature? | no
| Deprecations? | no
| Tickets | Part of #36872
| License | MIT
| Doc PR | N/A
PHP 8 uses double quotes instead of single ones in error messages. This PR teaches `ClassNotFoundFatalErrorHandler` to parse the new format.
Depends on composer/composer#9183
Commits
-------
275496a1f4
[Debug] Parse "x not found" errors correctly on php 8.
This commit is contained in:
commit
9460894ae2
@ -29,50 +29,34 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
|
|||||||
*/
|
*/
|
||||||
public function handleError(array $error, FatalErrorException $exception)
|
public function handleError(array $error, FatalErrorException $exception)
|
||||||
{
|
{
|
||||||
$messageLen = \strlen($error['message']);
|
if (!preg_match('/^(Class|Interface|Trait) [\'"]([^\'"]+)[\'"] not found$/', $error['message'], $matches)) {
|
||||||
$notFoundSuffix = '\' not found';
|
|
||||||
$notFoundSuffixLen = \strlen($notFoundSuffix);
|
|
||||||
if ($notFoundSuffixLen > $messageLen) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
$typeName = strtolower($matches[1]);
|
||||||
|
$fullyQualifiedClassName = $matches[2];
|
||||||
|
|
||||||
if (0 !== substr_compare($error['message'], $notFoundSuffix, -$notFoundSuffixLen)) {
|
if (false !== $namespaceSeparatorIndex = strrpos($fullyQualifiedClassName, '\\')) {
|
||||||
return null;
|
$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 = '?';
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (['class', 'interface', 'trait'] as $typeName) {
|
if ($candidates = $this->getClassCandidates($className)) {
|
||||||
$prefix = ucfirst($typeName).' \'';
|
$tail = array_pop($candidates).'"?';
|
||||||
$prefixLen = \strlen($prefix);
|
if ($candidates) {
|
||||||
if (0 !== strpos($error['message'], $prefix)) {
|
$tail = ' for e.g. "'.implode('", "', $candidates).'" or "'.$tail;
|
||||||
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 {
|
} else {
|
||||||
$className = $fullyQualifiedClassName;
|
$tail = ' for "'.$tail;
|
||||||
$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);
|
|
||||||
}
|
}
|
||||||
|
$message .= "\nDid you forget a \"use\" statement".$tail;
|
||||||
|
|
||||||
return null;
|
return new ClassNotFoundException($message, $exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -80,6 +80,15 @@ class ClassNotFoundFatalErrorHandlerTest extends TestCase
|
|||||||
$debugClassLoader = new DebugClassLoader([$autoloader, 'loadClass']);
|
$debugClassLoader = new DebugClassLoader([$autoloader, 'loadClass']);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
[
|
||||||
|
[
|
||||||
|
'type' => 1,
|
||||||
|
'line' => 12,
|
||||||
|
'file' => 'foo.php',
|
||||||
|
'message' => 'Class "WhizBangFactory" not found',
|
||||||
|
],
|
||||||
|
"/^Attempted to load class \"WhizBangFactory\" from the global namespace.\nDid you forget a \"use\" statement\?$/",
|
||||||
|
],
|
||||||
[
|
[
|
||||||
[
|
[
|
||||||
'type' => 1,
|
'type' => 1,
|
||||||
@ -98,6 +107,33 @@ class ClassNotFoundFatalErrorHandlerTest extends TestCase
|
|||||||
],
|
],
|
||||||
"/^Attempted to load class \"WhizBangFactory\" from namespace \"Foo\\\\Bar\".\nDid you forget a \"use\" statement for another namespace\?$/",
|
"/^Attempted to load class \"WhizBangFactory\" from namespace \"Foo\\\\Bar\".\nDid you forget a \"use\" statement for another namespace\?$/",
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
[
|
||||||
|
'type' => 1,
|
||||||
|
'line' => 12,
|
||||||
|
'file' => 'foo.php',
|
||||||
|
'message' => 'Class "Foo\\Bar\\WhizBangFactory" not found',
|
||||||
|
],
|
||||||
|
"/^Attempted to load class \"WhizBangFactory\" from namespace \"Foo\\\\Bar\".\nDid you forget a \"use\" statement for another namespace\?$/",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[
|
||||||
|
'type' => 1,
|
||||||
|
'line' => 12,
|
||||||
|
'file' => 'foo.php',
|
||||||
|
'message' => 'Interface "Foo\\Bar\\WhizBangInterface" not found',
|
||||||
|
],
|
||||||
|
"/^Attempted to load interface \"WhizBangInterface\" from namespace \"Foo\\\\Bar\".\nDid you forget a \"use\" statement for another namespace\?$/",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[
|
||||||
|
'type' => 1,
|
||||||
|
'line' => 12,
|
||||||
|
'file' => 'foo.php',
|
||||||
|
'message' => 'Trait "Foo\\Bar\\WhizBangTrait" not found',
|
||||||
|
],
|
||||||
|
"/^Attempted to load trait \"WhizBangTrait\" from namespace \"Foo\\\\Bar\".\nDid you forget a \"use\" statement for another namespace\?$/",
|
||||||
|
],
|
||||||
[
|
[
|
||||||
[
|
[
|
||||||
'type' => 1,
|
'type' => 1,
|
||||||
|
Reference in New Issue
Block a user