From aaa0cdf523ae148d26786f69512ac70f68db8658 Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Mon, 5 Aug 2019 16:25:47 +0200 Subject: [PATCH] [ErrorHandler] Rework fatal error handlers --- .../FrameworkBundle/Console/Application.php | 4 +- src/Symfony/Component/Console/Application.php | 4 +- .../Exception/ClassNotFoundException.php | 4 +- .../Debug/Exception/FatalErrorException.php | 4 +- .../Debug/Exception/FatalThrowableError.php | 4 +- .../Debug/Exception/OutOfMemoryException.php | 4 +- .../Exception/UndefinedFunctionException.php | 4 +- .../Exception/UndefinedMethodException.php | 4 +- .../UndefinedFunctionFatalErrorHandler.php | 4 +- .../UndefinedMethodFatalErrorHandler.php | 4 +- .../ErrorHandler/Error/ClassNotFoundError.php | 33 ++++ .../FatalError.php} | 43 +++-- .../OutOfMemoryError.php} | 9 +- .../Error/UndefinedFunctionError.php | 33 ++++ .../Error/UndefinedMethodError.php | 33 ++++ .../ClassNotFoundErrorEnhancer.php} | 28 +-- .../ErrorEnhancer/ErrorEnhancerInterface.php | 20 ++ .../UndefinedFunctionErrorEnhancer.php} | 27 +-- .../UndefinedMethodErrorEnhancer.php} | 23 ++- .../Component/ErrorHandler/ErrorHandler.php | 87 ++++----- .../Exception/ClassNotFoundException.php | 36 ---- ...lThrowableError.php => ErrorException.php} | 13 +- .../Exception/UndefinedFunctionException.php | 36 ---- .../Exception/UndefinedMethodException.php | 36 ---- .../FatalErrorHandlerInterface.php | 31 --- .../ClassNotFoundErrorEnhancerTest.php | 149 +++++++++++++++ .../UndefinedFunctionErrorEnhancerTest.php | 62 ++++++ .../UndefinedMethodErrorEnhancerTest.php | 57 ++++++ .../ErrorHandler/Tests/ErrorHandlerTest.php | 6 +- .../ClassNotFoundFatalErrorHandlerTest.php | 180 ------------------ ...UndefinedFunctionFatalErrorHandlerTest.php | 81 -------- .../UndefinedMethodFatalErrorHandlerTest.php | 76 -------- ...r.phpt => decorate_exception_handler.phpt} | 12 +- .../phpt/fatal_with_nested_handlers.phpt | 13 +- .../Exception/FlattenException.php | 4 +- .../Tests/Exception/FlattenExceptionTest.php | 4 +- .../EventListener/DebugHandlersListener.php | 6 +- 37 files changed, 546 insertions(+), 632 deletions(-) create mode 100644 src/Symfony/Component/ErrorHandler/Error/ClassNotFoundError.php rename src/Symfony/Component/ErrorHandler/{Exception/FatalErrorException.php => Error/FatalError.php} (68%) rename src/Symfony/Component/ErrorHandler/{Exception/OutOfMemoryException.php => Error/OutOfMemoryError.php} (56%) create mode 100644 src/Symfony/Component/ErrorHandler/Error/UndefinedFunctionError.php create mode 100644 src/Symfony/Component/ErrorHandler/Error/UndefinedMethodError.php rename src/Symfony/Component/ErrorHandler/{FatalErrorHandler/ClassNotFoundFatalErrorHandler.php => ErrorEnhancer/ClassNotFoundErrorEnhancer.php} (87%) create mode 100644 src/Symfony/Component/ErrorHandler/ErrorEnhancer/ErrorEnhancerInterface.php rename src/Symfony/Component/ErrorHandler/{FatalErrorHandler/UndefinedFunctionFatalErrorHandler.php => ErrorEnhancer/UndefinedFunctionErrorEnhancer.php} (75%) rename src/Symfony/Component/ErrorHandler/{FatalErrorHandler/UndefinedMethodFatalErrorHandler.php => ErrorEnhancer/UndefinedMethodErrorEnhancer.php} (73%) delete mode 100644 src/Symfony/Component/ErrorHandler/Exception/ClassNotFoundException.php rename src/Symfony/Component/ErrorHandler/Exception/{FatalThrowableError.php => ErrorException.php} (77%) delete mode 100644 src/Symfony/Component/ErrorHandler/Exception/UndefinedFunctionException.php delete mode 100644 src/Symfony/Component/ErrorHandler/Exception/UndefinedMethodException.php delete mode 100644 src/Symfony/Component/ErrorHandler/FatalErrorHandler/FatalErrorHandlerInterface.php create mode 100644 src/Symfony/Component/ErrorHandler/Tests/ErrorEnhancer/ClassNotFoundErrorEnhancerTest.php create mode 100644 src/Symfony/Component/ErrorHandler/Tests/ErrorEnhancer/UndefinedFunctionErrorEnhancerTest.php create mode 100644 src/Symfony/Component/ErrorHandler/Tests/ErrorEnhancer/UndefinedMethodErrorEnhancerTest.php delete mode 100644 src/Symfony/Component/ErrorHandler/Tests/FatalErrorHandler/ClassNotFoundFatalErrorHandlerTest.php delete mode 100644 src/Symfony/Component/ErrorHandler/Tests/FatalErrorHandler/UndefinedFunctionFatalErrorHandlerTest.php delete mode 100644 src/Symfony/Component/ErrorHandler/Tests/FatalErrorHandler/UndefinedMethodFatalErrorHandlerTest.php rename src/Symfony/Component/ErrorHandler/Tests/phpt/{decorate_exception_hander.phpt => decorate_exception_handler.phpt} (77%) diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Application.php b/src/Symfony/Bundle/FrameworkBundle/Console/Application.php index 08595ce917141..1b5be3bcc1b7f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Application.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Application.php @@ -20,7 +20,7 @@ use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\DependencyInjection\ContainerAwareInterface; -use Symfony\Component\ErrorHandler\Exception\FatalThrowableError; +use Symfony\Component\ErrorHandler\Exception\ErrorException; use Symfony\Component\HttpKernel\Bundle\Bundle; use Symfony\Component\HttpKernel\Kernel; use Symfony\Component\HttpKernel\KernelInterface; @@ -208,7 +208,7 @@ private function renderRegistrationErrors(InputInterface $input, OutputInterface foreach ($this->registrationErrors as $error) { if (!$error instanceof \Exception) { - $error = new FatalThrowableError($error); + $error = new ErrorException($error); } $this->doRenderException($error, $output); diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index e66705ab37bc6..995aceaf1907a 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -44,7 +44,7 @@ use Symfony\Component\Debug\ErrorHandler as LegacyErrorHandler; use Symfony\Component\Debug\Exception\FatalThrowableError as LegacyFatalThrowableError; use Symfony\Component\ErrorHandler\ErrorHandler; -use Symfony\Component\ErrorHandler\Exception\FatalThrowableError; +use Symfony\Component\ErrorHandler\Exception\ErrorException; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy; use Symfony\Contracts\Service\ResetInterface; @@ -129,7 +129,7 @@ public function run(InputInterface $input = null, OutputInterface $output = null $renderException = function (\Throwable $e) use ($output) { if (!$e instanceof \Exception) { - $e = class_exists(FatalThrowableError::class) ? new FatalThrowableError($e) : (class_exists(LegacyFatalThrowableError::class) ? new LegacyFatalThrowableError($e) : new \ErrorException($e->getMessage(), $e->getCode(), E_ERROR, $e->getFile(), $e->getLine())); + $e = class_exists(ErrorException::class) ? new ErrorException($e) : (class_exists(LegacyFatalThrowableError::class) ? new LegacyFatalThrowableError($e) : new \ErrorException($e->getMessage(), $e->getCode(), E_ERROR, $e->getFile(), $e->getLine())); } if ($output instanceof ConsoleOutputInterface) { $this->renderException($e, $output->getErrorOutput()); diff --git a/src/Symfony/Component/Debug/Exception/ClassNotFoundException.php b/src/Symfony/Component/Debug/Exception/ClassNotFoundException.php index 21e2c0db53a93..6c87f98c55be8 100644 --- a/src/Symfony/Component/Debug/Exception/ClassNotFoundException.php +++ b/src/Symfony/Component/Debug/Exception/ClassNotFoundException.php @@ -11,14 +11,14 @@ namespace Symfony\Component\Debug\Exception; -@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "%s" instead.', ClassNotFoundException::class, \Symfony\Component\ErrorHandler\Exception\ClassNotFoundException::class), E_USER_DEPRECATED); +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "%s" instead.', ClassNotFoundException::class, \Symfony\Component\ErrorHandler\Error\ClassNotFoundError::class), E_USER_DEPRECATED); /** * Class (or Trait or Interface) Not Found Exception. * * @author Konstanton Myakshin * - * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\Exception\ClassNotFoundException instead. + * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\Error\ClassNotFoundError instead. */ class ClassNotFoundException extends FatalErrorException { diff --git a/src/Symfony/Component/Debug/Exception/FatalErrorException.php b/src/Symfony/Component/Debug/Exception/FatalErrorException.php index 23c2ede7eb964..571f3975da494 100644 --- a/src/Symfony/Component/Debug/Exception/FatalErrorException.php +++ b/src/Symfony/Component/Debug/Exception/FatalErrorException.php @@ -11,14 +11,14 @@ namespace Symfony\Component\Debug\Exception; -@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "%s" instead.', FatalErrorException::class, \Symfony\Component\ErrorHandler\Exception\FatalErrorException::class), E_USER_DEPRECATED); +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "%s" instead.', FatalErrorException::class, \Symfony\Component\ErrorHandler\Exception\ErrorException::class), E_USER_DEPRECATED); /** * Fatal Error Exception. * * @author Konstanton Myakshin * - * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\Exception\FatalErrorException instead. + * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\Exception\ErrorException instead. */ class FatalErrorException extends \ErrorException { diff --git a/src/Symfony/Component/Debug/Exception/FatalThrowableError.php b/src/Symfony/Component/Debug/Exception/FatalThrowableError.php index d7d36ac17e312..53c410b014b1d 100644 --- a/src/Symfony/Component/Debug/Exception/FatalThrowableError.php +++ b/src/Symfony/Component/Debug/Exception/FatalThrowableError.php @@ -11,14 +11,14 @@ namespace Symfony\Component\Debug\Exception; -@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "%s" instead.', FatalThrowableError::class, \Symfony\Component\ErrorHandler\Exception\FatalThrowableError::class), E_USER_DEPRECATED); +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "%s" instead.', FatalThrowableError::class, \Symfony\Component\ErrorHandler\Exception\ErrorException::class), E_USER_DEPRECATED); /** * Fatal Throwable Error. * * @author Nicolas Grekas * - * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\Exception\FatalThrowableError instead. + * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\Exception\ErrorException instead. */ class FatalThrowableError extends FatalErrorException { diff --git a/src/Symfony/Component/Debug/Exception/OutOfMemoryException.php b/src/Symfony/Component/Debug/Exception/OutOfMemoryException.php index 5b02d52ad8bb2..a4a90ee997962 100644 --- a/src/Symfony/Component/Debug/Exception/OutOfMemoryException.php +++ b/src/Symfony/Component/Debug/Exception/OutOfMemoryException.php @@ -11,14 +11,14 @@ namespace Symfony\Component\Debug\Exception; -@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "%s" instead.', OutOfMemoryException::class, \Symfony\Component\ErrorHandler\Exception\OutOfMemoryException::class), E_USER_DEPRECATED); +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "%s" instead.', OutOfMemoryException::class, \Symfony\Component\ErrorHandler\Error\OutOfMemoryError::class), E_USER_DEPRECATED); /** * Out of memory exception. * * @author Nicolas Grekas * - * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\Exception\OutOfMemoryException instead. + * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\Error\OutOfMemoryError instead. */ class OutOfMemoryException extends FatalErrorException { diff --git a/src/Symfony/Component/Debug/Exception/UndefinedFunctionException.php b/src/Symfony/Component/Debug/Exception/UndefinedFunctionException.php index fefd7d248edaa..0a7037aee8310 100644 --- a/src/Symfony/Component/Debug/Exception/UndefinedFunctionException.php +++ b/src/Symfony/Component/Debug/Exception/UndefinedFunctionException.php @@ -11,14 +11,14 @@ namespace Symfony\Component\Debug\Exception; -@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "%s" instead.', UndefinedFunctionException::class, \Symfony\Component\ErrorHandler\Exception\UndefinedFunctionException::class), E_USER_DEPRECATED); +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "%s" instead.', UndefinedFunctionException::class, \Symfony\Component\ErrorHandler\Error\UndefinedFunctionError::class), E_USER_DEPRECATED); /** * Undefined Function Exception. * * @author Konstanton Myakshin * - * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\Exception\UndefinedFunctionException instead. + * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\Error\UndefinedFunctionError instead. */ class UndefinedFunctionException extends FatalErrorException { diff --git a/src/Symfony/Component/Debug/Exception/UndefinedMethodException.php b/src/Symfony/Component/Debug/Exception/UndefinedMethodException.php index 48559415868de..4d31c56d37e43 100644 --- a/src/Symfony/Component/Debug/Exception/UndefinedMethodException.php +++ b/src/Symfony/Component/Debug/Exception/UndefinedMethodException.php @@ -11,14 +11,14 @@ namespace Symfony\Component\Debug\Exception; -@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "%s" instead.', UndefinedMethodException::class, \Symfony\Component\ErrorHandler\Exception\UndefinedMethodException::class), E_USER_DEPRECATED); +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "%s" instead.', UndefinedMethodException::class, \Symfony\Component\ErrorHandler\Error\UndefinedMethodError::class), E_USER_DEPRECATED); /** * Undefined Method Exception. * * @author Grégoire Pineau * - * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\Exception\UndefinedMethodException instead. + * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\Error\UndefinedMethodError instead. */ class UndefinedMethodException extends FatalErrorException { diff --git a/src/Symfony/Component/Debug/FatalErrorHandler/UndefinedFunctionFatalErrorHandler.php b/src/Symfony/Component/Debug/FatalErrorHandler/UndefinedFunctionFatalErrorHandler.php index ce9f4c0bb9471..67b7ddd1610ee 100644 --- a/src/Symfony/Component/Debug/FatalErrorHandler/UndefinedFunctionFatalErrorHandler.php +++ b/src/Symfony/Component/Debug/FatalErrorHandler/UndefinedFunctionFatalErrorHandler.php @@ -14,14 +14,14 @@ use Symfony\Component\Debug\Exception\FatalErrorException; use Symfony\Component\Debug\Exception\UndefinedFunctionException; -@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "%s" instead.', UndefinedFunctionFatalErrorHandler::class, \Symfony\Component\ErrorHandler\FatalErrorHandler\UndefinedFunctionFatalErrorHandler::class), E_USER_DEPRECATED); +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "%s" instead.', UndefinedFunctionFatalErrorHandler::class, \Symfony\Component\ErrorHandler\ErrorEnhancer\UndefinedFunctionErrorEnhancer::class), E_USER_DEPRECATED); /** * ErrorHandler for undefined functions. * * @author Fabien Potencier * - * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\FatalErrorHandler\UndefinedFunctionFatalErrorHandler instead. + * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\ErrorEnhancer\UndefinedFunctionErrorEnhancer instead. */ class UndefinedFunctionFatalErrorHandler implements FatalErrorHandlerInterface { diff --git a/src/Symfony/Component/Debug/FatalErrorHandler/UndefinedMethodFatalErrorHandler.php b/src/Symfony/Component/Debug/FatalErrorHandler/UndefinedMethodFatalErrorHandler.php index 4fa3e46cd5991..8ee359ab27771 100644 --- a/src/Symfony/Component/Debug/FatalErrorHandler/UndefinedMethodFatalErrorHandler.php +++ b/src/Symfony/Component/Debug/FatalErrorHandler/UndefinedMethodFatalErrorHandler.php @@ -14,14 +14,14 @@ use Symfony\Component\Debug\Exception\FatalErrorException; use Symfony\Component\Debug\Exception\UndefinedMethodException; -@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "%s" instead.', UndefinedMethodFatalErrorHandler::class, \Symfony\Component\ErrorHandler\FatalErrorHandler\UndefinedMethodFatalErrorHandler::class), E_USER_DEPRECATED); +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "%s" instead.', UndefinedMethodFatalErrorHandler::class, \Symfony\Component\ErrorHandler\ErrorEnhancer\UndefinedMethodErrorEnhancer::class), E_USER_DEPRECATED); /** * ErrorHandler for undefined methods. * * @author Grégoire Pineau * - * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\FatalErrorHandler\UndefinedMethodFatalErrorHandler instead. + * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\ErrorEnhancer\UndefinedMethodErrorEnhancer instead. */ class UndefinedMethodFatalErrorHandler implements FatalErrorHandlerInterface { diff --git a/src/Symfony/Component/ErrorHandler/Error/ClassNotFoundError.php b/src/Symfony/Component/ErrorHandler/Error/ClassNotFoundError.php new file mode 100644 index 0000000000000..443fba2c3bee6 --- /dev/null +++ b/src/Symfony/Component/ErrorHandler/Error/ClassNotFoundError.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ErrorHandler\Error; + +class ClassNotFoundError extends \Error +{ + /** + * {@inheritdoc} + */ + public function __construct(string $message, \Throwable $previous) + { + parent::__construct($message, $previous->getCode(), $previous->getPrevious()); + + foreach ([ + 'file' => $previous->getFile(), + 'line' => $previous->getLine(), + 'trace' => $previous->getTrace(), + ] as $property => $value) { + $refl = new \ReflectionProperty(\Error::class, $property); + $refl->setAccessible(true); + $refl->setValue($this, $value); + } + } +} diff --git a/src/Symfony/Component/ErrorHandler/Exception/FatalErrorException.php b/src/Symfony/Component/ErrorHandler/Error/FatalError.php similarity index 68% rename from src/Symfony/Component/ErrorHandler/Exception/FatalErrorException.php rename to src/Symfony/Component/ErrorHandler/Error/FatalError.php index ab6268a5c0412..68172d876cb51 100644 --- a/src/Symfony/Component/ErrorHandler/Exception/FatalErrorException.php +++ b/src/Symfony/Component/ErrorHandler/Error/FatalError.php @@ -9,18 +9,22 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\ErrorHandler\Exception; +namespace Symfony\Component\ErrorHandler\Error; -/** - * Fatal Error Exception. - * - * @author Konstanton Myakshin - */ -class FatalErrorException extends \ErrorException +class FatalError extends \Error { - public function __construct(string $message, int $code, int $severity, string $filename, int $lineno, int $traceOffset = null, bool $traceArgs = true, array $trace = null, \Throwable $previous = null) + private $error; + + /** + * {@inheritdoc} + * + * @param array $error An array as returned by error_get_last() + */ + public function __construct(string $message, int $code, array $error, int $traceOffset = null, bool $traceArgs = true, array $trace = null) { - parent::__construct($message, $code, $severity, $filename, $lineno, $previous); + parent::__construct($message, $code); + + $this->error = $error; if (null !== $trace) { if (!$traceArgs) { @@ -28,8 +32,6 @@ public function __construct(string $message, int $code, int $severity, string $f unset($frame['args'], $frame['this'], $frame); } } - - $this->setTrace($trace); } elseif (null !== $traceOffset) { if (\function_exists('xdebug_get_function_stack')) { $trace = xdebug_get_function_stack(); @@ -63,15 +65,24 @@ public function __construct(string $message, int $code, int $severity, string $f } else { $trace = []; } + } - $this->setTrace($trace); + foreach ([ + 'file' => $error['file'], + 'line' => $error['line'], + 'trace' => $trace, + ] as $property => $value) { + $refl = new \ReflectionProperty(\Error::class, $property); + $refl->setAccessible(true); + $refl->setValue($this, $value); } } - protected function setTrace(array $trace): void + /** + * {@inheritdoc} + */ + public function getError(): array { - $traceReflector = new \ReflectionProperty('Exception', 'trace'); - $traceReflector->setAccessible(true); - $traceReflector->setValue($this, $trace); + return $this->error; } } diff --git a/src/Symfony/Component/ErrorHandler/Exception/OutOfMemoryException.php b/src/Symfony/Component/ErrorHandler/Error/OutOfMemoryError.php similarity index 56% rename from src/Symfony/Component/ErrorHandler/Exception/OutOfMemoryException.php rename to src/Symfony/Component/ErrorHandler/Error/OutOfMemoryError.php index 18c367596f630..d685c3d369336 100644 --- a/src/Symfony/Component/ErrorHandler/Exception/OutOfMemoryException.php +++ b/src/Symfony/Component/ErrorHandler/Error/OutOfMemoryError.php @@ -9,13 +9,8 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\ErrorHandler\Exception; +namespace Symfony\Component\ErrorHandler\Error; -/** - * Out of memory exception. - * - * @author Nicolas Grekas - */ -class OutOfMemoryException extends FatalErrorException +class OutOfMemoryError extends FatalError { } diff --git a/src/Symfony/Component/ErrorHandler/Error/UndefinedFunctionError.php b/src/Symfony/Component/ErrorHandler/Error/UndefinedFunctionError.php new file mode 100644 index 0000000000000..b57dd1579dee6 --- /dev/null +++ b/src/Symfony/Component/ErrorHandler/Error/UndefinedFunctionError.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ErrorHandler\Error; + +class UndefinedFunctionError extends \Error +{ + /** + * {@inheritdoc} + */ + public function __construct(string $message, \Throwable $previous) + { + parent::__construct($message, $previous->getCode(), $previous->getPrevious()); + + foreach ([ + 'file' => $previous->getFile(), + 'line' => $previous->getLine(), + 'trace' => $previous->getTrace(), + ] as $property => $value) { + $refl = new \ReflectionProperty(\Error::class, $property); + $refl->setAccessible(true); + $refl->setValue($this, $value); + } + } +} diff --git a/src/Symfony/Component/ErrorHandler/Error/UndefinedMethodError.php b/src/Symfony/Component/ErrorHandler/Error/UndefinedMethodError.php new file mode 100644 index 0000000000000..adc8731f36c48 --- /dev/null +++ b/src/Symfony/Component/ErrorHandler/Error/UndefinedMethodError.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ErrorHandler\Error; + +class UndefinedMethodError extends \Error +{ + /** + * {@inheritdoc} + */ + public function __construct(string $message, \Throwable $previous) + { + parent::__construct($message, $previous->getCode(), $previous->getPrevious()); + + foreach ([ + 'file' => $previous->getFile(), + 'line' => $previous->getLine(), + 'trace' => $previous->getTrace(), + ] as $property => $value) { + $refl = new \ReflectionProperty(\Error::class, $property); + $refl->setAccessible(true); + $refl->setValue($this, $value); + } + } +} diff --git a/src/Symfony/Component/ErrorHandler/FatalErrorHandler/ClassNotFoundFatalErrorHandler.php b/src/Symfony/Component/ErrorHandler/ErrorEnhancer/ClassNotFoundErrorEnhancer.php similarity index 87% rename from src/Symfony/Component/ErrorHandler/FatalErrorHandler/ClassNotFoundFatalErrorHandler.php rename to src/Symfony/Component/ErrorHandler/ErrorEnhancer/ClassNotFoundErrorEnhancer.php index ee9930c097858..38111078bc311 100644 --- a/src/Symfony/Component/ErrorHandler/FatalErrorHandler/ClassNotFoundFatalErrorHandler.php +++ b/src/Symfony/Component/ErrorHandler/ErrorEnhancer/ClassNotFoundErrorEnhancer.php @@ -9,45 +9,45 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\ErrorHandler\FatalErrorHandler; +namespace Symfony\Component\ErrorHandler\ErrorEnhancer; use Composer\Autoload\ClassLoader as ComposerClassLoader; use Symfony\Component\ClassLoader\ClassLoader as SymfonyClassLoader; use Symfony\Component\ErrorHandler\DebugClassLoader; -use Symfony\Component\ErrorHandler\Exception\ClassNotFoundException; -use Symfony\Component\ErrorHandler\Exception\FatalErrorException; +use Symfony\Component\ErrorHandler\Error\ClassNotFoundError; +use Symfony\Component\ErrorHandler\Error\FatalError; /** - * ErrorHandler for classes that do not exist. - * * @author Fabien Potencier */ -class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface +class ClassNotFoundErrorEnhancer implements ErrorEnhancerInterface { /** * {@inheritdoc} */ - public function handleError(array $error, FatalErrorException $exception) + public function enhance(\Throwable $error): ?\Throwable { - $messageLen = \strlen($error['message']); + // Some specific versions of PHP produce a fatal error when extending a not found class. + $message = !$error instanceof FatalError ? $error->getMessage() : $error->getError()['message']; + $messageLen = \strlen($message); $notFoundSuffix = '\' not found'; $notFoundSuffixLen = \strlen($notFoundSuffix); if ($notFoundSuffixLen > $messageLen) { return null; } - if (0 !== substr_compare($error['message'], $notFoundSuffix, -$notFoundSuffixLen)) { + if (0 !== substr_compare($message, $notFoundSuffix, -$notFoundSuffixLen)) { return null; } foreach (['class', 'interface', 'trait'] as $typeName) { $prefix = ucfirst($typeName).' \''; $prefixLen = \strlen($prefix); - if (0 !== strpos($error['message'], $prefix)) { + if (0 !== strpos($message, $prefix)) { continue; } - $fullyQualifiedClassName = substr($error['message'], $prefixLen, -$notFoundSuffixLen); + $fullyQualifiedClassName = substr($message, $prefixLen, -$notFoundSuffixLen); if (false !== $namespaceSeparatorIndex = strrpos($fullyQualifiedClassName, '\\')) { $className = substr($fullyQualifiedClassName, $namespaceSeparatorIndex + 1); $namespacePrefix = substr($fullyQualifiedClassName, 0, $namespaceSeparatorIndex); @@ -69,8 +69,10 @@ public function handleError(array $error, FatalErrorException $exception) } $message .= "\nDid you forget a \"use\" statement".$tail; - return new ClassNotFoundException($message, $exception); + return new ClassNotFoundError($message, $error); } + + return null; } /** @@ -81,7 +83,7 @@ public function handleError(array $error, FatalErrorException $exception) * * @param string $class A class name (without its namespace) * - * @return array An array of possible fully qualified class names + * Returns an array of possible fully qualified class names */ private function getClassCandidates(string $class): array { diff --git a/src/Symfony/Component/ErrorHandler/ErrorEnhancer/ErrorEnhancerInterface.php b/src/Symfony/Component/ErrorHandler/ErrorEnhancer/ErrorEnhancerInterface.php new file mode 100644 index 0000000000000..7c3f4ef94068a --- /dev/null +++ b/src/Symfony/Component/ErrorHandler/ErrorEnhancer/ErrorEnhancerInterface.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ErrorHandler\ErrorEnhancer; + +interface ErrorEnhancerInterface +{ + /** + * Returns an \Throwable instance if the class is able to improve the error, null otherwise. + */ + public function enhance(\Throwable $error): ?\Throwable; +} diff --git a/src/Symfony/Component/ErrorHandler/FatalErrorHandler/UndefinedFunctionFatalErrorHandler.php b/src/Symfony/Component/ErrorHandler/ErrorEnhancer/UndefinedFunctionErrorEnhancer.php similarity index 75% rename from src/Symfony/Component/ErrorHandler/FatalErrorHandler/UndefinedFunctionFatalErrorHandler.php rename to src/Symfony/Component/ErrorHandler/ErrorEnhancer/UndefinedFunctionErrorEnhancer.php index b944b8e11cd87..f4c49c2856c22 100644 --- a/src/Symfony/Component/ErrorHandler/FatalErrorHandler/UndefinedFunctionFatalErrorHandler.php +++ b/src/Symfony/Component/ErrorHandler/ErrorEnhancer/UndefinedFunctionErrorEnhancer.php @@ -9,41 +9,44 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\ErrorHandler\FatalErrorHandler; +namespace Symfony\Component\ErrorHandler\ErrorEnhancer; -use Symfony\Component\ErrorHandler\Exception\FatalErrorException; -use Symfony\Component\ErrorHandler\Exception\UndefinedFunctionException; +use Symfony\Component\ErrorHandler\Error\FatalError; +use Symfony\Component\ErrorHandler\Error\UndefinedFunctionError; /** - * ErrorHandler for undefined functions. - * * @author Fabien Potencier */ -class UndefinedFunctionFatalErrorHandler implements FatalErrorHandlerInterface +class UndefinedFunctionErrorEnhancer implements ErrorEnhancerInterface { /** * {@inheritdoc} */ - public function handleError(array $error, FatalErrorException $exception) + public function enhance(\Throwable $error): ?\Throwable { - $messageLen = \strlen($error['message']); + if ($error instanceof FatalError) { + return null; + } + + $message = $error->getMessage(); + $messageLen = \strlen($message); $notFoundSuffix = '()'; $notFoundSuffixLen = \strlen($notFoundSuffix); if ($notFoundSuffixLen > $messageLen) { return null; } - if (0 !== substr_compare($error['message'], $notFoundSuffix, -$notFoundSuffixLen)) { + if (0 !== substr_compare($message, $notFoundSuffix, -$notFoundSuffixLen)) { return null; } $prefix = 'Call to undefined function '; $prefixLen = \strlen($prefix); - if (0 !== strpos($error['message'], $prefix)) { + if (0 !== strpos($message, $prefix)) { return null; } - $fullyQualifiedFunctionName = substr($error['message'], $prefixLen, -$notFoundSuffixLen); + $fullyQualifiedFunctionName = substr($message, $prefixLen, -$notFoundSuffixLen); if (false !== $namespaceSeparatorIndex = strrpos($fullyQualifiedFunctionName, '\\')) { $functionName = substr($fullyQualifiedFunctionName, $namespaceSeparatorIndex + 1); $namespacePrefix = substr($fullyQualifiedFunctionName, 0, $namespaceSeparatorIndex); @@ -79,6 +82,6 @@ public function handleError(array $error, FatalErrorException $exception) $message .= "\nDid you mean to call ".$candidates; } - return new UndefinedFunctionException($message, $exception); + return new UndefinedFunctionError($message, $error); } } diff --git a/src/Symfony/Component/ErrorHandler/FatalErrorHandler/UndefinedMethodFatalErrorHandler.php b/src/Symfony/Component/ErrorHandler/ErrorEnhancer/UndefinedMethodErrorEnhancer.php similarity index 73% rename from src/Symfony/Component/ErrorHandler/FatalErrorHandler/UndefinedMethodFatalErrorHandler.php rename to src/Symfony/Component/ErrorHandler/ErrorEnhancer/UndefinedMethodErrorEnhancer.php index 90bb09837e6da..ad0e4b3eef00b 100644 --- a/src/Symfony/Component/ErrorHandler/FatalErrorHandler/UndefinedMethodFatalErrorHandler.php +++ b/src/Symfony/Component/ErrorHandler/ErrorEnhancer/UndefinedMethodErrorEnhancer.php @@ -9,24 +9,27 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\ErrorHandler\FatalErrorHandler; +namespace Symfony\Component\ErrorHandler\ErrorEnhancer; -use Symfony\Component\ErrorHandler\Exception\FatalErrorException; -use Symfony\Component\ErrorHandler\Exception\UndefinedMethodException; +use Symfony\Component\ErrorHandler\Error\FatalError; +use Symfony\Component\ErrorHandler\Error\UndefinedMethodError; /** - * ErrorHandler for undefined methods. - * * @author Grégoire Pineau */ -class UndefinedMethodFatalErrorHandler implements FatalErrorHandlerInterface +class UndefinedMethodErrorEnhancer implements ErrorEnhancerInterface { /** * {@inheritdoc} */ - public function handleError(array $error, FatalErrorException $exception) + public function enhance(\Throwable $error): ?\Throwable { - preg_match('/^Call to undefined method (.*)::(.*)\(\)$/', $error['message'], $matches); + if ($error instanceof FatalError) { + return null; + } + + $message = $error->getMessage(); + preg_match('/^Call to undefined method (.*)::(.*)\(\)$/', $message, $matches); if (!$matches) { return null; } @@ -38,7 +41,7 @@ public function handleError(array $error, FatalErrorException $exception) if (!class_exists($className) || null === $methods = get_class_methods($className)) { // failed to get the class or its methods on which an unknown method was called (for example on an anonymous class) - return new UndefinedMethodException($message, $exception); + return new UndefinedMethodError($message, $error); } $candidates = []; @@ -61,6 +64,6 @@ public function handleError(array $error, FatalErrorException $exception) $message .= "\nDid you mean to call ".$candidates; } - return new UndefinedMethodException($message, $exception); + return new UndefinedMethodError($message, $error); } } diff --git a/src/Symfony/Component/ErrorHandler/ErrorHandler.php b/src/Symfony/Component/ErrorHandler/ErrorHandler.php index 37047911f7033..5bb43df04dbcd 100644 --- a/src/Symfony/Component/ErrorHandler/ErrorHandler.php +++ b/src/Symfony/Component/ErrorHandler/ErrorHandler.php @@ -13,15 +13,13 @@ use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; -use Symfony\Component\ErrorHandler\Exception\FatalErrorException; -use Symfony\Component\ErrorHandler\Exception\OutOfMemoryException; +use Symfony\Component\ErrorHandler\Error\FatalError; +use Symfony\Component\ErrorHandler\Error\OutOfMemoryError; +use Symfony\Component\ErrorHandler\ErrorEnhancer\ClassNotFoundErrorEnhancer; +use Symfony\Component\ErrorHandler\ErrorEnhancer\ErrorEnhancerInterface; +use Symfony\Component\ErrorHandler\ErrorEnhancer\UndefinedFunctionErrorEnhancer; +use Symfony\Component\ErrorHandler\ErrorEnhancer\UndefinedMethodErrorEnhancer; use Symfony\Component\ErrorHandler\Exception\SilencedErrorContext; -use Symfony\Component\ErrorHandler\FatalErrorHandler\ClassNotFoundFatalErrorHandler; -use Symfony\Component\ErrorHandler\FatalErrorHandler\FatalErrorHandlerInterface; -use Symfony\Component\ErrorHandler\FatalErrorHandler\UndefinedFunctionFatalErrorHandler; -use Symfony\Component\ErrorHandler\FatalErrorHandler\UndefinedMethodFatalErrorHandler; -use Symfony\Component\ErrorRenderer\ErrorRenderer\HtmlErrorRenderer; -use Symfony\Component\ErrorRenderer\Exception\FlattenException; /** * A generic ErrorHandler for the PHP engine. @@ -538,64 +536,50 @@ public function handleError(int $type, string $message, string $file, int $line) /** * Handles an exception by logging then forwarding it to another handler. * - * @param array $error An array as returned by error_get_last() - * * @internal */ - public function handleException(\Throwable $exception, array $error = null) + public function handleException(\Throwable $exception) { - if (null === $error) { + $handlerException = null; + + if (!$exception instanceof FatalError) { self::$exitCode = 255; - } - $type = ThrowableUtils::getSeverity($exception); - $handlerException = null; + $type = ThrowableUtils::getSeverity($exception); + } else { + $type = $exception->getError()['type']; + } - if (($this->loggedErrors & $type) || $exception instanceof \Error) { + if ($this->loggedErrors & $type) { if (false !== strpos($message = $exception->getMessage(), "class@anonymous\0")) { $message = $this->parseAnonymousClass($message); } - if ($exception instanceof FatalErrorException) { + if ($exception instanceof FatalError) { $message = 'Fatal '.$message; - } elseif ($exception instanceof \ErrorException) { - $message = 'Uncaught '.$message; } elseif ($exception instanceof \Error) { - $error = [ - 'type' => $type, - 'message' => $message, - 'file' => $exception->getFile(), - 'line' => $exception->getLine(), - ]; $message = 'Uncaught Error: '.$message; + } elseif ($exception instanceof \ErrorException) { + $message = 'Uncaught '.$message; } else { $message = 'Uncaught Exception: '.$message; } - } - if ($this->loggedErrors & $type) { try { $this->loggers[$type][0]->log($this->loggers[$type][1], $message, ['exception' => $exception]); } catch (\Throwable $handlerException) { } } - // temporary until fatal error handlers rework - $originalException = $exception; - if (!$exception instanceof \Exception) { - $exception = new FatalErrorException($exception->getMessage(), $exception->getCode(), $type, $exception->getFile(), $exception->getLine(), null, true, $exception->getTrace()); - } - - if ($exception instanceof FatalErrorException && !$exception instanceof OutOfMemoryException && $error) { - foreach ($this->getFatalErrorHandlers() as $handler) { - if ($e = $handler->handleError($error, $exception)) { - $convertedException = $e; + if (!$exception instanceof OutOfMemoryError) { + foreach ($this->getErrorEnhancers() as $errorEnhancer) { + if ($e = $errorEnhancer->enhance($exception)) { + $exception = $e; break; } } } - $exception = $convertedException ?? $originalException; $exceptionHandler = $this->exceptionHandler; if ((!\is_array($exceptionHandler) || !$exceptionHandler[0] instanceof self || 'sendPhpResponse' !== $exceptionHandler[1]) && !\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) { $this->exceptionHandler = [$this, 'sendPhpResponse']; @@ -613,6 +597,7 @@ public function handleException(\Throwable $exception, array $error = null) self::$reservedMemory = null; // Disable the fatal error handler throw $exception; // Give back $exception to the native handler } + $this->handleException($handlerException); } @@ -673,20 +658,20 @@ public static function handleFatalError(array $error = null): void $trace = isset($error['backtrace']) ? $error['backtrace'] : null; if (0 === strpos($error['message'], 'Allowed memory') || 0 === strpos($error['message'], 'Out of memory')) { - $exception = new OutOfMemoryException($handler->levels[$error['type']].': '.$error['message'], 0, $error['type'], $error['file'], $error['line'], 2, false, $trace); + $fatalError = new OutOfMemoryError($handler->levels[$error['type']].': '.$error['message'], 0, $error, 2, false, $trace); } else { - $exception = new FatalErrorException($handler->levels[$error['type']].': '.$error['message'], 0, $error['type'], $error['file'], $error['line'], 2, true, $trace); + $fatalError = new FatalError($handler->levels[$error['type']].': '.$error['message'], 0, $error, 2, true, $trace); } } else { - $exception = null; + $fatalError = null; } try { - if (null !== $exception) { + if (null !== $fatalError) { self::$exitCode = 255; - $handler->handleException($exception, $error); + $handler->handleException($fatalError); } - } catch (FatalErrorException $e) { + } catch (FatalError $e) { // Ignore this re-throw } @@ -730,18 +715,16 @@ private function sendPhpResponse(\Throwable $exception) } /** - * Gets the fatal error handlers. - * - * Override this method if you want to define more fatal error handlers. + * Override this method if you want to define more error enhancers. * - * @return FatalErrorHandlerInterface[] An array of FatalErrorHandlerInterface + * @return ErrorEnhancerInterface[] */ - protected function getFatalErrorHandlers(): array + protected function getErrorEnhancers(): iterable { return [ - new UndefinedFunctionFatalErrorHandler(), - new UndefinedMethodFatalErrorHandler(), - new ClassNotFoundFatalErrorHandler(), + new UndefinedFunctionErrorEnhancer(), + new UndefinedMethodErrorEnhancer(), + new ClassNotFoundErrorEnhancer(), ]; } diff --git a/src/Symfony/Component/ErrorHandler/Exception/ClassNotFoundException.php b/src/Symfony/Component/ErrorHandler/Exception/ClassNotFoundException.php deleted file mode 100644 index b0638826d6414..0000000000000 --- a/src/Symfony/Component/ErrorHandler/Exception/ClassNotFoundException.php +++ /dev/null @@ -1,36 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\ErrorHandler\Exception; - -/** - * Class (or Trait or Interface) Not Found Exception. - * - * @author Konstanton Myakshin - */ -class ClassNotFoundException extends FatalErrorException -{ - public function __construct(string $message, \ErrorException $previous) - { - parent::__construct( - $message, - $previous->getCode(), - $previous->getSeverity(), - $previous->getFile(), - $previous->getLine(), - null, - true, - null, - $previous->getPrevious() - ); - $this->setTrace($previous->getTrace()); - } -} diff --git a/src/Symfony/Component/ErrorHandler/Exception/FatalThrowableError.php b/src/Symfony/Component/ErrorHandler/Exception/ErrorException.php similarity index 77% rename from src/Symfony/Component/ErrorHandler/Exception/FatalThrowableError.php rename to src/Symfony/Component/ErrorHandler/Exception/ErrorException.php index 460d3e1ae832d..759d3fdc47a3f 100644 --- a/src/Symfony/Component/ErrorHandler/Exception/FatalThrowableError.php +++ b/src/Symfony/Component/ErrorHandler/Exception/ErrorException.php @@ -13,12 +13,7 @@ use Symfony\Component\ErrorHandler\ThrowableUtils; -/** - * Fatal Throwable Error. - * - * @author Nicolas Grekas - */ -class FatalThrowableError extends FatalErrorException +class ErrorException extends \ErrorException { private $originalClassName; @@ -26,7 +21,7 @@ public function __construct(\Throwable $e) { $this->originalClassName = \get_class($e); - \ErrorException::__construct( + parent::__construct( $e->getMessage(), $e->getCode(), ThrowableUtils::getSeverity($e), @@ -35,7 +30,9 @@ public function __construct(\Throwable $e) $e->getPrevious() ); - $this->setTrace($e->getTrace()); + $refl = new \ReflectionProperty(\Exception::class, 'trace'); + $refl->setAccessible(true); + $refl->setValue($this, $e->getTrace()); } public function getOriginalClassName(): string diff --git a/src/Symfony/Component/ErrorHandler/Exception/UndefinedFunctionException.php b/src/Symfony/Component/ErrorHandler/Exception/UndefinedFunctionException.php deleted file mode 100644 index bb2f46564d4d7..0000000000000 --- a/src/Symfony/Component/ErrorHandler/Exception/UndefinedFunctionException.php +++ /dev/null @@ -1,36 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\ErrorHandler\Exception; - -/** - * Undefined Function Exception. - * - * @author Konstanton Myakshin - */ -class UndefinedFunctionException extends FatalErrorException -{ - public function __construct(string $message, \ErrorException $previous) - { - parent::__construct( - $message, - $previous->getCode(), - $previous->getSeverity(), - $previous->getFile(), - $previous->getLine(), - null, - true, - null, - $previous->getPrevious() - ); - $this->setTrace($previous->getTrace()); - } -} diff --git a/src/Symfony/Component/ErrorHandler/Exception/UndefinedMethodException.php b/src/Symfony/Component/ErrorHandler/Exception/UndefinedMethodException.php deleted file mode 100644 index 12efdc716c5dc..0000000000000 --- a/src/Symfony/Component/ErrorHandler/Exception/UndefinedMethodException.php +++ /dev/null @@ -1,36 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\ErrorHandler\Exception; - -/** - * Undefined Method Exception. - * - * @author Grégoire Pineau - */ -class UndefinedMethodException extends FatalErrorException -{ - public function __construct(string $message, \ErrorException $previous) - { - parent::__construct( - $message, - $previous->getCode(), - $previous->getSeverity(), - $previous->getFile(), - $previous->getLine(), - null, - true, - null, - $previous->getPrevious() - ); - $this->setTrace($previous->getTrace()); - } -} diff --git a/src/Symfony/Component/ErrorHandler/FatalErrorHandler/FatalErrorHandlerInterface.php b/src/Symfony/Component/ErrorHandler/FatalErrorHandler/FatalErrorHandlerInterface.php deleted file mode 100644 index daf5dcd1fdd12..0000000000000 --- a/src/Symfony/Component/ErrorHandler/FatalErrorHandler/FatalErrorHandlerInterface.php +++ /dev/null @@ -1,31 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\ErrorHandler\FatalErrorHandler; - -use Symfony\Component\ErrorHandler\Exception\FatalErrorException; - -/** - * Attempts to convert fatal errors to exceptions. - * - * @author Fabien Potencier - */ -interface FatalErrorHandlerInterface -{ - /** - * Attempts to convert an error into an exception. - * - * @param array $error An array as returned by error_get_last() - * - * @return FatalErrorException|null A FatalErrorException instance if the class is able to convert the error, null otherwise - */ - public function handleError(array $error, FatalErrorException $exception); -} diff --git a/src/Symfony/Component/ErrorHandler/Tests/ErrorEnhancer/ClassNotFoundErrorEnhancerTest.php b/src/Symfony/Component/ErrorHandler/Tests/ErrorEnhancer/ClassNotFoundErrorEnhancerTest.php new file mode 100644 index 0000000000000..3098200b01604 --- /dev/null +++ b/src/Symfony/Component/ErrorHandler/Tests/ErrorEnhancer/ClassNotFoundErrorEnhancerTest.php @@ -0,0 +1,149 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ErrorHandler\Tests\ErrorEnhancer; + +use Composer\Autoload\ClassLoader as ComposerClassLoader; +use PHPUnit\Framework\TestCase; +use Symfony\Component\ErrorHandler\DebugClassLoader; +use Symfony\Component\ErrorHandler\Error\ClassNotFoundError; +use Symfony\Component\ErrorHandler\Error\FatalError; +use Symfony\Component\ErrorHandler\ErrorEnhancer\ClassNotFoundErrorEnhancer; + +class ClassNotFoundErrorEnhancerTest extends TestCase +{ + public static function setUpBeforeClass(): void + { + foreach (spl_autoload_functions() as $function) { + if (!\is_array($function)) { + continue; + } + + // get class loaders wrapped by DebugClassLoader + if ($function[0] instanceof DebugClassLoader) { + $function = $function[0]->getClassLoader(); + } + + if ($function[0] instanceof ComposerClassLoader) { + $function[0]->add('Symfony_Component_ErrorHandler_Tests_Fixtures', \dirname(__DIR__, 5)); + break; + } + } + } + + /** + * @dataProvider provideClassNotFoundData + */ + public function testEnhance(string $originalMessage, string $enhancedMessage, $autoloader = null) + { + try { + if ($autoloader) { + // Unregister all autoloaders to ensure the custom provided + // autoloader is the only one to be used during the test run. + $autoloaders = spl_autoload_functions(); + array_map('spl_autoload_unregister', $autoloaders); + spl_autoload_register($autoloader); + } + + $expectedLine = __LINE__ + 1; + $error = (new ClassNotFoundErrorEnhancer())->enhance(new \Error($originalMessage)); + } finally { + if ($autoloader) { + spl_autoload_unregister($autoloader); + array_map('spl_autoload_register', $autoloaders); + } + } + + $this->assertInstanceOf(ClassNotFoundError::class, $error); + $this->assertSame($enhancedMessage, $error->getMessage()); + $this->assertSame(realpath(__FILE__), $error->getFile()); + $this->assertSame($expectedLine, $error->getLine()); + } + + public function provideClassNotFoundData() + { + $autoloader = new ComposerClassLoader(); + $autoloader->add('Symfony\Component\ErrorHandler\Error\\', realpath(__DIR__.'/../../Error')); + $autoloader->add('Symfony_Component_ErrorHandler_Tests_Fixtures', realpath(__DIR__.'/../../Tests/Fixtures')); + + $debugClassLoader = new DebugClassLoader([$autoloader, 'loadClass']); + + return [ + [ + 'Class \'WhizBangFactory\' not found', + "Attempted to load class \"WhizBangFactory\" from the global namespace.\nDid you forget a \"use\" statement?", + ], + [ + 'Class \'Foo\\Bar\\WhizBangFactory\' not found', + "Attempted to load class \"WhizBangFactory\" from namespace \"Foo\\Bar\".\nDid you forget a \"use\" statement for another namespace?", + ], + [ + 'Class \'UndefinedFunctionError\' not found', + "Attempted to load class \"UndefinedFunctionError\" from the global namespace.\nDid you forget a \"use\" statement for \"Symfony\Component\ErrorHandler\Error\UndefinedFunctionError\"?", + [$debugClassLoader, 'loadClass'], + ], + [ + 'Class \'PEARClass\' not found', + "Attempted to load class \"PEARClass\" from the global namespace.\nDid you forget a \"use\" statement for \"Symfony_Component_ErrorHandler_Tests_Fixtures_PEARClass\"?", + [$debugClassLoader, 'loadClass'], + ], + [ + 'Class \'Foo\\Bar\\UndefinedFunctionError\' not found', + "Attempted to load class \"UndefinedFunctionError\" from namespace \"Foo\Bar\".\nDid you forget a \"use\" statement for \"Symfony\Component\ErrorHandler\Error\UndefinedFunctionError\"?", + [$debugClassLoader, 'loadClass'], + ], + [ + 'Class \'Foo\\Bar\\UndefinedFunctionError\' not found', + "Attempted to load class \"UndefinedFunctionError\" from namespace \"Foo\Bar\".\nDid you forget a \"use\" statement for \"Symfony\Component\ErrorHandler\Error\UndefinedFunctionError\"?", + [$autoloader, 'loadClass'], + ], + [ + 'Class \'Foo\\Bar\\UndefinedFunctionError\' not found', + "Attempted to load class \"UndefinedFunctionError\" from namespace \"Foo\Bar\".\nDid you forget a \"use\" statement for \"Symfony\Component\ErrorHandler\Error\UndefinedFunctionError\"?", + [$debugClassLoader, 'loadClass'], + ], + [ + 'Class \'Foo\\Bar\\UndefinedFunctionError\' not found', + "Attempted to load class \"UndefinedFunctionError\" from namespace \"Foo\\Bar\".\nDid you forget a \"use\" statement for another namespace?", + function ($className) { /* do nothing here */ }, + ], + ]; + } + + public function testEnhanceWithFatalError() + { + $error = (new ClassNotFoundErrorEnhancer())->enhance(new FatalError('foo', 0, [ + 'type' => E_ERROR, + 'message' => "Class 'FooBarCcc' not found", + 'file' => $expectedFile = realpath(__FILE__), + 'line' => $expectedLine = __LINE__, + ])); + + $this->assertInstanceOf(ClassNotFoundError::class, $error); + $this->assertSame("Attempted to load class \"FooBarCcc\" from the global namespace.\nDid you forget a \"use\" statement?", $error->getMessage()); + $this->assertSame($expectedFile, $error->getFile()); + $this->assertSame($expectedLine, $error->getLine()); + } + + public function testCannotRedeclareClass() + { + if (!file_exists(__DIR__.'/../FIXTURES2/REQUIREDTWICE.PHP')) { + $this->markTestSkipped('Can only be run on case insensitive filesystems'); + } + + require_once __DIR__.'/../FIXTURES2/REQUIREDTWICE.PHP'; + + $enhancer = new ClassNotFoundErrorEnhancer(); + $error = $enhancer->enhance(new \Error("Class 'Foo\\Bar\\RequiredTwice' not found")); + + $this->assertInstanceOf(ClassNotFoundError::class, $error); + } +} diff --git a/src/Symfony/Component/ErrorHandler/Tests/ErrorEnhancer/UndefinedFunctionErrorEnhancerTest.php b/src/Symfony/Component/ErrorHandler/Tests/ErrorEnhancer/UndefinedFunctionErrorEnhancerTest.php new file mode 100644 index 0000000000000..fe7d5371a11ae --- /dev/null +++ b/src/Symfony/Component/ErrorHandler/Tests/ErrorEnhancer/UndefinedFunctionErrorEnhancerTest.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ErrorHandler\Tests\ErrorEnhancer; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\ErrorHandler\Error\UndefinedFunctionError; +use Symfony\Component\ErrorHandler\ErrorEnhancer\UndefinedFunctionErrorEnhancer; + +class UndefinedFunctionErrorEnhancerTest extends TestCase +{ + /** + * @dataProvider provideUndefinedFunctionData + */ + public function testEnhance(string $originalMessage, string $enhancedMessage) + { + $enhancer = new UndefinedFunctionErrorEnhancer(); + + $expectedLine = __LINE__ + 1; + $error = $enhancer->enhance(new \Error($originalMessage)); + + $this->assertInstanceOf(UndefinedFunctionError::class, $error); + // class names are case insensitive and PHP do not return the same + $this->assertSame(strtolower($enhancedMessage), strtolower($error->getMessage())); + $this->assertSame(realpath(__FILE__), $error->getFile()); + $this->assertSame($expectedLine, $error->getLine()); + } + + public function provideUndefinedFunctionData() + { + return [ + [ + 'Call to undefined function test_namespaced_function()', + "Attempted to call function \"test_namespaced_function\" from the global namespace.\nDid you mean to call \"\\symfony\\component\\errorhandler\\tests\\errorenhancer\\test_namespaced_function\"?", + ], + [ + 'Call to undefined function Foo\\Bar\\Baz\\test_namespaced_function()', + "Attempted to call function \"test_namespaced_function\" from namespace \"Foo\\Bar\\Baz\".\nDid you mean to call \"\\symfony\\component\\errorhandler\\tests\\errorenhancer\\test_namespaced_function\"?", + ], + [ + 'Call to undefined function foo()', + 'Attempted to call function "foo" from the global namespace.', + ], + [ + 'Call to undefined function Foo\\Bar\\Baz\\foo()', + 'Attempted to call function "foo" from namespace "Foo\Bar\Baz".', + ], + ]; + } +} + +function test_namespaced_function() +{ +} diff --git a/src/Symfony/Component/ErrorHandler/Tests/ErrorEnhancer/UndefinedMethodErrorEnhancerTest.php b/src/Symfony/Component/ErrorHandler/Tests/ErrorEnhancer/UndefinedMethodErrorEnhancerTest.php new file mode 100644 index 0000000000000..d6ac6c029c6fb --- /dev/null +++ b/src/Symfony/Component/ErrorHandler/Tests/ErrorEnhancer/UndefinedMethodErrorEnhancerTest.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ErrorHandler\Tests\ErrorEnhancer; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\ErrorHandler\Error\UndefinedMethodError; +use Symfony\Component\ErrorHandler\ErrorEnhancer\UndefinedMethodErrorEnhancer; + +class UndefinedMethodErrorEnhancerTest extends TestCase +{ + /** + * @dataProvider provideUndefinedMethodData + */ + public function testEnhance(string $originalMessage, string $enhancedMessage) + { + $enhancer = new UndefinedMethodErrorEnhancer(); + + $expectedLine = __LINE__ + 1; + $error = $enhancer->enhance(new \Error($originalMessage)); + + $this->assertInstanceOf(UndefinedMethodError::class, $error); + $this->assertSame($enhancedMessage, $error->getMessage()); + $this->assertSame(realpath(__FILE__), $error->getFile()); + $this->assertSame($expectedLine, $error->getLine()); + } + + public function provideUndefinedMethodData() + { + return [ + [ + 'Call to undefined method SplObjectStorage::what()', + 'Attempted to call an undefined method named "what" of class "SplObjectStorage".', + ], + [ + 'Call to undefined method SplObjectStorage::walid()', + "Attempted to call an undefined method named \"walid\" of class \"SplObjectStorage\".\nDid you mean to call \"valid\"?", + ], + [ + 'Call to undefined method SplObjectStorage::offsetFet()', + "Attempted to call an undefined method named \"offsetFet\" of class \"SplObjectStorage\".\nDid you mean to call e.g. \"offsetGet\", \"offsetSet\" or \"offsetUnset\"?", + ], + [ + 'Call to undefined method class@anonymous::test()', + 'Attempted to call an undefined method named "test" of class "class@anonymous".', + ], + ]; + } +} diff --git a/src/Symfony/Component/ErrorHandler/Tests/ErrorHandlerTest.php b/src/Symfony/Component/ErrorHandler/Tests/ErrorHandlerTest.php index bb694cfc3bc5c..1c170732e8983 100644 --- a/src/Symfony/Component/ErrorHandler/Tests/ErrorHandlerTest.php +++ b/src/Symfony/Component/ErrorHandler/Tests/ErrorHandlerTest.php @@ -15,6 +15,8 @@ use Psr\Log\LogLevel; use Psr\Log\NullLogger; use Symfony\Component\ErrorHandler\BufferingLogger; +use Symfony\Component\ErrorHandler\Error\ClassNotFoundError; +use Symfony\Component\ErrorHandler\Error\FatalError; use Symfony\Component\ErrorHandler\ErrorHandler; use Symfony\Component\ErrorHandler\Exception\SilencedErrorContext; use Symfony\Component\ErrorHandler\Tests\Fixtures\ErrorHandlerThatUsesThePreviousOne; @@ -518,7 +520,7 @@ public function testHandleFatalError() $logArgCheck = function ($level, $message, $context) { $this->assertEquals('Fatal Parse Error: foo', $message); $this->assertArrayHasKey('exception', $context); - $this->assertInstanceOf(\Exception::class, $context['exception']); + $this->assertInstanceOf(FatalError::class, $context['exception']); }; $logger @@ -552,7 +554,7 @@ public function testHandleErrorException() $handler->handleException($exception); - $this->assertInstanceOf('Symfony\Component\ErrorHandler\Exception\ClassNotFoundException', $args[0]); + $this->assertInstanceOf(ClassNotFoundError::class, $args[0]); $this->assertStringStartsWith("Attempted to load class \"IReallyReallyDoNotExistAnywhereInTheRepositoryISwear\" from the global namespace.\nDid you forget a \"use\" statement", $args[0]->getMessage()); } diff --git a/src/Symfony/Component/ErrorHandler/Tests/FatalErrorHandler/ClassNotFoundFatalErrorHandlerTest.php b/src/Symfony/Component/ErrorHandler/Tests/FatalErrorHandler/ClassNotFoundFatalErrorHandlerTest.php deleted file mode 100644 index 0661d742c03c0..0000000000000 --- a/src/Symfony/Component/ErrorHandler/Tests/FatalErrorHandler/ClassNotFoundFatalErrorHandlerTest.php +++ /dev/null @@ -1,180 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\ErrorHandler\Tests\FatalErrorHandler; - -use Composer\Autoload\ClassLoader as ComposerClassLoader; -use PHPUnit\Framework\TestCase; -use Symfony\Component\ErrorHandler\DebugClassLoader; -use Symfony\Component\ErrorHandler\Exception\FatalErrorException; -use Symfony\Component\ErrorHandler\FatalErrorHandler\ClassNotFoundFatalErrorHandler; - -class ClassNotFoundFatalErrorHandlerTest extends TestCase -{ - public static function setUpBeforeClass(): void - { - foreach (spl_autoload_functions() as $function) { - if (!\is_array($function)) { - continue; - } - - // get class loaders wrapped by DebugClassLoader - if ($function[0] instanceof DebugClassLoader) { - $function = $function[0]->getClassLoader(); - } - - if ($function[0] instanceof ComposerClassLoader) { - $function[0]->add('Symfony_Component_ErrorHandler_Tests_Fixtures', \dirname(__DIR__, 5)); - break; - } - } - } - - /** - * @dataProvider provideClassNotFoundData - */ - public function testHandleClassNotFound(array $error, string $translatedMessage, callable $autoloader = null) - { - if ($autoloader) { - // Unregister all autoloaders to ensure the custom provided - // autoloader is the only one to be used during the test run. - $autoloaders = spl_autoload_functions(); - array_map('spl_autoload_unregister', $autoloaders); - spl_autoload_register($autoloader); - } - - $handler = new ClassNotFoundFatalErrorHandler(); - - $exception = $handler->handleError($error, new FatalErrorException('', 0, $error['type'], $error['file'], $error['line'])); - - if ($autoloader) { - spl_autoload_unregister($autoloader); - array_map('spl_autoload_register', $autoloaders); - } - - $this->assertInstanceOf('Symfony\Component\ErrorHandler\Exception\ClassNotFoundException', $exception); - $this->assertSame($translatedMessage, $exception->getMessage()); - $this->assertSame($error['type'], $exception->getSeverity()); - $this->assertSame($error['file'], $exception->getFile()); - $this->assertSame($error['line'], $exception->getLine()); - } - - public function provideClassNotFoundData(): array - { - $autoloader = new ComposerClassLoader(); - $autoloader->add('Symfony\Component\ErrorHandler\Exception\\', realpath(__DIR__.'/../../Exception')); - $autoloader->add('Symfony_Component_ErrorHandler_Tests_Fixtures', realpath(__DIR__.'/../../Tests/Fixtures')); - - $debugClassLoader = new DebugClassLoader([$autoloader, 'loadClass']); - - 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, - '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' => 'Class \'UndefinedFunctionException\' not found', - ], - "Attempted to load class \"UndefinedFunctionException\" from the global namespace.\nDid you forget a \"use\" statement for \"Symfony\Component\ErrorHandler\Exception\UndefinedFunctionException\"?", - [$debugClassLoader, 'loadClass'], - ], - [ - [ - 'type' => 1, - 'line' => 12, - 'file' => 'foo.php', - 'message' => 'Class \'PEARClass\' not found', - ], - "Attempted to load class \"PEARClass\" from the global namespace.\nDid you forget a \"use\" statement for \"Symfony_Component_ErrorHandler_Tests_Fixtures_PEARClass\"?", - [$debugClassLoader, 'loadClass'], - ], - [ - [ - 'type' => 1, - 'line' => 12, - 'file' => 'foo.php', - 'message' => 'Class \'Foo\\Bar\\UndefinedFunctionException\' not found', - ], - "Attempted to load class \"UndefinedFunctionException\" from namespace \"Foo\Bar\".\nDid you forget a \"use\" statement for \"Symfony\Component\ErrorHandler\Exception\UndefinedFunctionException\"?", - [$debugClassLoader, 'loadClass'], - ], - [ - [ - 'type' => 1, - 'line' => 12, - 'file' => 'foo.php', - 'message' => 'Class \'Foo\\Bar\\UndefinedFunctionException\' not found', - ], - "Attempted to load class \"UndefinedFunctionException\" from namespace \"Foo\Bar\".\nDid you forget a \"use\" statement for \"Symfony\Component\ErrorHandler\Exception\UndefinedFunctionException\"?", - [$autoloader, 'loadClass'], - ], - [ - [ - 'type' => 1, - 'line' => 12, - 'file' => 'foo.php', - 'message' => 'Class \'Foo\\Bar\\UndefinedFunctionException\' not found', - ], - "Attempted to load class \"UndefinedFunctionException\" from namespace \"Foo\Bar\".\nDid you forget a \"use\" statement for \"Symfony\Component\ErrorHandler\Exception\UndefinedFunctionException\"?", - [$debugClassLoader, 'loadClass'], - ], - [ - [ - 'type' => 1, - 'line' => 12, - 'file' => 'foo.php', - 'message' => 'Class \'Foo\\Bar\\UndefinedFunctionException\' not found', - ], - "Attempted to load class \"UndefinedFunctionException\" from namespace \"Foo\\Bar\".\nDid you forget a \"use\" statement for another namespace?", - function ($className) { /* do nothing here */ }, - ], - ]; - } - - public function testCannotRedeclareClass() - { - if (!file_exists(__DIR__.'/../FIXTURES2/REQUIREDTWICE.PHP')) { - $this->markTestSkipped('Can only be run on case insensitive filesystems'); - } - - require_once __DIR__.'/../FIXTURES2/REQUIREDTWICE.PHP'; - - $error = [ - 'type' => 1, - 'line' => 12, - 'file' => 'foo.php', - 'message' => 'Class \'Foo\\Bar\\RequiredTwice\' not found', - ]; - - $handler = new ClassNotFoundFatalErrorHandler(); - $exception = $handler->handleError($error, new FatalErrorException('', 0, $error['type'], $error['file'], $error['line'])); - - $this->assertInstanceOf('Symfony\Component\ErrorHandler\Exception\ClassNotFoundException', $exception); - } -} diff --git a/src/Symfony/Component/ErrorHandler/Tests/FatalErrorHandler/UndefinedFunctionFatalErrorHandlerTest.php b/src/Symfony/Component/ErrorHandler/Tests/FatalErrorHandler/UndefinedFunctionFatalErrorHandlerTest.php deleted file mode 100644 index fa8dd42268dae..0000000000000 --- a/src/Symfony/Component/ErrorHandler/Tests/FatalErrorHandler/UndefinedFunctionFatalErrorHandlerTest.php +++ /dev/null @@ -1,81 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\ErrorHandler\Tests\FatalErrorHandler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\ErrorHandler\Exception\FatalErrorException; -use Symfony\Component\ErrorHandler\FatalErrorHandler\UndefinedFunctionFatalErrorHandler; - -class UndefinedFunctionFatalErrorHandlerTest extends TestCase -{ - /** - * @dataProvider provideUndefinedFunctionData - */ - public function testUndefinedFunction(array $error, string $translatedMessage) - { - $handler = new UndefinedFunctionFatalErrorHandler(); - $exception = $handler->handleError($error, new FatalErrorException('', 0, $error['type'], $error['file'], $error['line'])); - - $this->assertInstanceOf('Symfony\Component\ErrorHandler\Exception\UndefinedFunctionException', $exception); - // class names are case insensitive and PHP do not return the same - $this->assertSame(strtolower($translatedMessage), strtolower($exception->getMessage())); - $this->assertSame($error['type'], $exception->getSeverity()); - $this->assertSame($error['file'], $exception->getFile()); - $this->assertSame($error['line'], $exception->getLine()); - } - - public function provideUndefinedFunctionData(): array - { - return [ - [ - [ - 'type' => 1, - 'line' => 12, - 'file' => 'foo.php', - 'message' => 'Call to undefined function test_namespaced_function()', - ], - "Attempted to call function \"test_namespaced_function\" from the global namespace.\nDid you mean to call \"\\symfony\\component\\errorhandler\\tests\\fatalerrorhandler\\test_namespaced_function\"?", - ], - [ - [ - 'type' => 1, - 'line' => 12, - 'file' => 'foo.php', - 'message' => 'Call to undefined function Foo\\Bar\\Baz\\test_namespaced_function()', - ], - "Attempted to call function \"test_namespaced_function\" from namespace \"Foo\\Bar\\Baz\".\nDid you mean to call \"\\symfony\\component\\errorhandler\\tests\\fatalerrorhandler\\test_namespaced_function\"?", - ], - [ - [ - 'type' => 1, - 'line' => 12, - 'file' => 'foo.php', - 'message' => 'Call to undefined function foo()', - ], - 'Attempted to call function "foo" from the global namespace.', - ], - [ - [ - 'type' => 1, - 'line' => 12, - 'file' => 'foo.php', - 'message' => 'Call to undefined function Foo\\Bar\\Baz\\foo()', - ], - 'Attempted to call function "foo" from namespace "Foo\Bar\Baz".', - ], - ]; - } -} - -function test_namespaced_function() -{ -} diff --git a/src/Symfony/Component/ErrorHandler/Tests/FatalErrorHandler/UndefinedMethodFatalErrorHandlerTest.php b/src/Symfony/Component/ErrorHandler/Tests/FatalErrorHandler/UndefinedMethodFatalErrorHandlerTest.php deleted file mode 100644 index 17414e1eb925b..0000000000000 --- a/src/Symfony/Component/ErrorHandler/Tests/FatalErrorHandler/UndefinedMethodFatalErrorHandlerTest.php +++ /dev/null @@ -1,76 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\ErrorHandler\Tests\FatalErrorHandler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\ErrorHandler\Exception\FatalErrorException; -use Symfony\Component\ErrorHandler\FatalErrorHandler\UndefinedMethodFatalErrorHandler; - -class UndefinedMethodFatalErrorHandlerTest extends TestCase -{ - /** - * @dataProvider provideUndefinedMethodData - */ - public function testUndefinedMethod(array $error, string $translatedMessage) - { - $handler = new UndefinedMethodFatalErrorHandler(); - $exception = $handler->handleError($error, new FatalErrorException('', 0, $error['type'], $error['file'], $error['line'])); - - $this->assertInstanceOf('Symfony\Component\ErrorHandler\Exception\UndefinedMethodException', $exception); - $this->assertSame($translatedMessage, $exception->getMessage()); - $this->assertSame($error['type'], $exception->getSeverity()); - $this->assertSame($error['file'], $exception->getFile()); - $this->assertSame($error['line'], $exception->getLine()); - } - - public function provideUndefinedMethodData(): array - { - return [ - [ - [ - 'type' => 1, - 'line' => 12, - 'file' => 'foo.php', - 'message' => 'Call to undefined method SplObjectStorage::what()', - ], - 'Attempted to call an undefined method named "what" of class "SplObjectStorage".', - ], - [ - [ - 'type' => 1, - 'line' => 12, - 'file' => 'foo.php', - 'message' => 'Call to undefined method SplObjectStorage::walid()', - ], - "Attempted to call an undefined method named \"walid\" of class \"SplObjectStorage\".\nDid you mean to call \"valid\"?", - ], - [ - [ - 'type' => 1, - 'line' => 12, - 'file' => 'foo.php', - 'message' => 'Call to undefined method SplObjectStorage::offsetFet()', - ], - "Attempted to call an undefined method named \"offsetFet\" of class \"SplObjectStorage\".\nDid you mean to call e.g. \"offsetGet\", \"offsetSet\" or \"offsetUnset\"?", - ], - [ - [ - 'type' => 1, - 'message' => 'Call to undefined method class@anonymous::test()', - 'file' => '/home/possum/work/symfony/test.php', - 'line' => 11, - ], - 'Attempted to call an undefined method named "test" of class "class@anonymous".', - ], - ]; - } -} diff --git a/src/Symfony/Component/ErrorHandler/Tests/phpt/decorate_exception_hander.phpt b/src/Symfony/Component/ErrorHandler/Tests/phpt/decorate_exception_handler.phpt similarity index 77% rename from src/Symfony/Component/ErrorHandler/Tests/phpt/decorate_exception_hander.phpt rename to src/Symfony/Component/ErrorHandler/Tests/phpt/decorate_exception_handler.phpt index 034d5a5292a44..5fb5981d2d027 100644 --- a/src/Symfony/Component/ErrorHandler/Tests/phpt/decorate_exception_hander.phpt +++ b/src/Symfony/Component/ErrorHandler/Tests/phpt/decorate_exception_handler.phpt @@ -23,14 +23,12 @@ if (true) { { } } - -?> --EXPECTF-- -object(Symfony\Component\ErrorHandler\Exception\ClassNotFoundException)#%d (8) { +object(Symfony\Component\ErrorHandler\Error\ClassNotFoundError)#%d (7) { ["message":protected]=> string(138) "Attempted to load class "missing" from namespace "Symfony\Component\ErrorHandler". Did you forget a "use" statement for another namespace?" - ["string":"Exception":private]=> + ["string":"Error":private]=> string(0) "" ["code":protected]=> int(0) @@ -38,10 +36,8 @@ Did you forget a "use" statement for another namespace?" string(%d) "%s" ["line":protected]=> int(%d) - ["trace":"Exception":private]=> + ["trace":"Error":private]=> array(%d) {%A} - ["previous":"Exception":private]=> + ["previous":"Error":private]=> NULL - ["severity":protected]=> - int(1) } diff --git a/src/Symfony/Component/ErrorHandler/Tests/phpt/fatal_with_nested_handlers.phpt b/src/Symfony/Component/ErrorHandler/Tests/phpt/fatal_with_nested_handlers.phpt index 532fe922410cb..15933828bd426 100644 --- a/src/Symfony/Component/ErrorHandler/Tests/phpt/fatal_with_nested_handlers.phpt +++ b/src/Symfony/Component/ErrorHandler/Tests/phpt/fatal_with_nested_handlers.phpt @@ -35,7 +35,18 @@ array(1) { [0]=> string(37) "Error and exception handlers do match" } -object(Symfony\Component\ErrorHandler\Exception\FatalErrorException)#%d (%d) { +object(Symfony\Component\ErrorHandler\Error\FatalError)#%d (%d) { + ["error":"Symfony\Component\ErrorHandler\Error\FatalError":private]=> + array(4) { + ["type"]=> + int(1) + ["message"]=> + string(179) "Class Symfony\Component\ErrorHandler\Broken contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (JsonSerializable::jsonSerialize)" + ["file"]=> + string(%d) "%s" + ["line"]=> + int(%d) + } ["message":protected]=> string(186) "Error: Class Symfony\Component\ErrorHandler\Broken contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (JsonSerializable::jsonSerialize)" %a diff --git a/src/Symfony/Component/ErrorRenderer/Exception/FlattenException.php b/src/Symfony/Component/ErrorRenderer/Exception/FlattenException.php index 56a5221ed86ca..7c053a328d330 100644 --- a/src/Symfony/Component/ErrorRenderer/Exception/FlattenException.php +++ b/src/Symfony/Component/ErrorRenderer/Exception/FlattenException.php @@ -11,7 +11,7 @@ namespace Symfony\Component\ErrorRenderer\Exception; -use Symfony\Component\ErrorHandler\Exception\FatalThrowableError; +use Symfony\Component\ErrorHandler\Exception\ErrorException; use Symfony\Component\HttpFoundation\Exception\RequestExceptionInterface; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; @@ -64,7 +64,7 @@ public static function createFromThrowable(\Throwable $exception, int $statusCod $e->setStatusCode($statusCode); $e->setHeaders($headers); $e->setTraceFromThrowable($exception); - $e->setClass($exception instanceof FatalThrowableError ? $exception->getOriginalClassName() : \get_class($exception)); + $e->setClass($exception instanceof ErrorException ? $exception->getOriginalClassName() : \get_class($exception)); $e->setFile($exception->getFile()); $e->setLine($exception->getLine()); diff --git a/src/Symfony/Component/ErrorRenderer/Tests/Exception/FlattenExceptionTest.php b/src/Symfony/Component/ErrorRenderer/Tests/Exception/FlattenExceptionTest.php index 7651e57f11d7b..dc2678be8158a 100644 --- a/src/Symfony/Component/ErrorRenderer/Tests/Exception/FlattenExceptionTest.php +++ b/src/Symfony/Component/ErrorRenderer/Tests/Exception/FlattenExceptionTest.php @@ -12,7 +12,7 @@ namespace Symfony\Component\ErrorRenderer\Tests\Exception; use PHPUnit\Framework\TestCase; -use Symfony\Component\ErrorHandler\Exception\FatalThrowableError; +use Symfony\Component\ErrorHandler\Exception\ErrorException; use Symfony\Component\ErrorRenderer\Exception\FlattenException; use Symfony\Component\HttpFoundation\Exception\SuspiciousOperationException; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; @@ -132,7 +132,7 @@ public function testFlattenHttpException(\Throwable $exception) public function testWrappedThrowable() { - $exception = new FatalThrowableError(new \DivisionByZeroError('Ouch', 42)); + $exception = new ErrorException(new \DivisionByZeroError('Ouch', 42)); $flattened = FlattenException::createFromThrowable($exception); $this->assertSame('Ouch', $flattened->getMessage(), 'The message is copied from the original error.'); diff --git a/src/Symfony/Component/HttpKernel/EventListener/DebugHandlersListener.php b/src/Symfony/Component/HttpKernel/EventListener/DebugHandlersListener.php index 03885a46b8645..edff2d45d0e59 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/DebugHandlersListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/DebugHandlersListener.php @@ -16,7 +16,7 @@ use Symfony\Component\Console\Event\ConsoleEvent; use Symfony\Component\Console\Output\ConsoleOutputInterface; use Symfony\Component\ErrorHandler\ErrorHandler; -use Symfony\Component\ErrorHandler\Exception\FatalThrowableError; +use Symfony\Component\ErrorHandler\Exception\ErrorException; use Symfony\Component\EventDispatcher\Event; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Debug\FileLinkFormatter; @@ -113,7 +113,7 @@ public function configure(Event $event = null) } if (!$e instanceof \Exception) { - $e = new FatalThrowableError($e); + $e = new ErrorException($e); } $hasRun = true; @@ -127,7 +127,7 @@ public function configure(Event $event = null) } $this->exceptionHandler = static function (\Throwable $e) use ($app, $output) { if (!$e instanceof \Exception) { - $e = new FatalThrowableError($e); + $e = new ErrorException($e); } $app->renderException($e, $output); pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy