Skip to content

Commit 62483ed

Browse files
committed
[ErrorHandler] Forward \Throwable
1 parent 51ffc18 commit 62483ed

File tree

7 files changed

+98
-47
lines changed

7 files changed

+98
-47
lines changed

src/Symfony/Bundle/FrameworkBundle/Console/Application.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -174,10 +174,8 @@ protected function registerCommands()
174174
if ($bundle instanceof Bundle) {
175175
try {
176176
$bundle->registerCommands($this);
177-
} catch (\Exception $e) {
178-
$this->registrationErrors[] = $e;
179177
} catch (\Throwable $e) {
180-
$this->registrationErrors[] = new FatalThrowableError($e);
178+
$this->registrationErrors[] = $e;
181179
}
182180
}
183181
}
@@ -192,10 +190,8 @@ protected function registerCommands()
192190
if (!isset($lazyCommandIds[$id])) {
193191
try {
194192
$this->add($container->get($id));
195-
} catch (\Exception $e) {
196-
$this->registrationErrors[] = $e;
197193
} catch (\Throwable $e) {
198-
$this->registrationErrors[] = new FatalThrowableError($e);
194+
$this->registrationErrors[] = $e;
199195
}
200196
}
201197
}
@@ -211,6 +207,10 @@ private function renderRegistrationErrors(InputInterface $input, OutputInterface
211207
(new SymfonyStyle($input, $output))->warning('Some commands could not be registered:');
212208

213209
foreach ($this->registrationErrors as $error) {
210+
if (!$error instanceof \Exception) {
211+
$error = new FatalThrowableError($error);
212+
}
213+
214214
$this->doRenderException($error, $output);
215215
}
216216
}

src/Symfony/Component/Console/Application.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ public function run(InputInterface $input = null, OutputInterface $output = null
127127
$output = new ConsoleOutput();
128128
}
129129

130-
$renderException = function ($e) use ($output) {
130+
$renderException = function (\Throwable $e) use ($output) {
131131
if (!$e instanceof \Exception) {
132132
$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()));
133133
}

src/Symfony/Component/ErrorHandler/ErrorHandler.php

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
use Psr\Log\LoggerInterface;
1515
use Psr\Log\LogLevel;
1616
use Symfony\Component\ErrorHandler\Exception\FatalErrorException;
17-
use Symfony\Component\ErrorHandler\Exception\FatalThrowableError;
1817
use Symfony\Component\ErrorHandler\Exception\OutOfMemoryException;
1918
use Symfony\Component\ErrorHandler\Exception\SilencedErrorContext;
2019
use Symfony\Component\ErrorHandler\FatalErrorHandler\ClassNotFoundFatalErrorHandler;
@@ -266,7 +265,7 @@ public function setLoggers(array $loggers): array
266265

267266
if ($flush) {
268267
foreach ($this->bootstrappingLogger->cleanLogs() as $log) {
269-
$type = $log[2]['exception'] instanceof \ErrorException ? $log[2]['exception']->getSeverity() : E_ERROR;
268+
$type = ThrowableUtils::getSeverity($log[2]['exception']);
270269
if (!isset($flush[$type])) {
271270
$this->bootstrappingLogger->log($log[0], $log[1], $log[2]);
272271
} elseif ($this->loggers[$type][0]) {
@@ -281,7 +280,7 @@ public function setLoggers(array $loggers): array
281280
/**
282281
* Sets a user exception handler.
283282
*
284-
* @param callable|null $handler A handler that will be called on Exception
283+
* @param callable|null $handler A handler that must support \Throwable instances that will be called on Exception
285284
*
286285
* @return callable|null The previous exception handler
287286
*/
@@ -540,57 +539,64 @@ public function handleError(int $type, string $message, string $file, int $line)
540539
/**
541540
* Handles an exception by logging then forwarding it to another handler.
542541
*
543-
* @param \Exception|\Throwable $exception An exception to handle
544-
* @param array $error An array as returned by error_get_last()
542+
* @param array $error An array as returned by error_get_last()
545543
*
546544
* @internal
547545
*/
548-
public function handleException($exception, array $error = null)
546+
public function handleException(\Throwable $exception, array $error = null)
549547
{
550548
if (null === $error) {
551549
self::$exitCode = 255;
552550
}
553-
if (!$exception instanceof \Exception) {
554-
$exception = new FatalThrowableError($exception);
555-
}
556-
$type = $exception instanceof FatalErrorException ? $exception->getSeverity() : E_ERROR;
551+
552+
$type = ThrowableUtils::getSeverity($exception);
557553
$handlerException = null;
558554

559-
if (($this->loggedErrors & $type) || $exception instanceof FatalThrowableError) {
555+
if (($this->loggedErrors & $type) || $exception instanceof \Error) {
560556
if (false !== strpos($message = $exception->getMessage(), "class@anonymous\0")) {
561557
$message = $this->parseAnonymousClass($message);
562558
}
559+
563560
if ($exception instanceof FatalErrorException) {
564-
if ($exception instanceof FatalThrowableError) {
565-
$error = [
566-
'type' => $type,
567-
'message' => $message,
568-
'file' => $exception->getFile(),
569-
'line' => $exception->getLine(),
570-
];
571-
} else {
572-
$message = 'Fatal '.$message;
573-
}
561+
$message = 'Fatal '.$message;
574562
} elseif ($exception instanceof \ErrorException) {
575563
$message = 'Uncaught '.$message;
564+
} elseif ($exception instanceof \Error) {
565+
$error = [
566+
'type' => $type,
567+
'message' => $message,
568+
'file' => $exception->getFile(),
569+
'line' => $exception->getLine(),
570+
];
571+
$message = 'Uncaught Error: '.$message;
576572
} else {
577573
$message = 'Uncaught Exception: '.$message;
578574
}
579575
}
576+
580577
if ($this->loggedErrors & $type) {
581578
try {
582579
$this->loggers[$type][0]->log($this->loggers[$type][1], $message, ['exception' => $exception]);
583580
} catch (\Throwable $handlerException) {
584581
}
585582
}
583+
584+
// temporary until fatal error handlers rework
585+
$originalException = $exception;
586+
if (!$exception instanceof \Exception) {
587+
$exception = new FatalErrorException($exception->getMessage(), $exception->getCode(), $type, $exception->getFile(), $exception->getLine(), null, true, $exception->getTrace());
588+
}
589+
586590
if ($exception instanceof FatalErrorException && !$exception instanceof OutOfMemoryException && $error) {
587591
foreach ($this->getFatalErrorHandlers() as $handler) {
588592
if ($e = $handler->handleError($error, $exception)) {
589-
$exception = $e;
593+
$convertedException = $e;
590594
break;
591595
}
592596
}
593597
}
598+
599+
$exception = $convertedException ?? $originalException;
594600
$exceptionHandler = $this->exceptionHandler;
595601
if ((!\is_array($exceptionHandler) || !$exceptionHandler[0] instanceof self || 'sendPhpResponse' !== $exceptionHandler[1]) && !\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) {
596602
$this->exceptionHandler = [$this, 'sendPhpResponse'];

src/Symfony/Component/ErrorHandler/Exception/FatalThrowableError.php

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
namespace Symfony\Component\ErrorHandler\Exception;
1313

14+
use Symfony\Component\ErrorHandler\ThrowableUtils;
15+
1416
/**
1517
* Fatal Throwable Error.
1618
*
@@ -24,18 +26,10 @@ public function __construct(\Throwable $e)
2426
{
2527
$this->originalClassName = \get_class($e);
2628

27-
if ($e instanceof \ParseError) {
28-
$severity = E_PARSE;
29-
} elseif ($e instanceof \TypeError) {
30-
$severity = E_RECOVERABLE_ERROR;
31-
} else {
32-
$severity = E_ERROR;
33-
}
34-
3529
\ErrorException::__construct(
3630
$e->getMessage(),
3731
$e->getCode(),
38-
$severity,
32+
ThrowableUtils::getSeverity($e),
3933
$e->getFile(),
4034
$e->getLine(),
4135
$e->getPrevious()

src/Symfony/Component/ErrorHandler/Tests/ErrorHandlerTest.php

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -382,18 +382,19 @@ public function testHandleDeprecation()
382382
restore_error_handler();
383383
}
384384

385-
public function testHandleException()
385+
/**
386+
* @dataProvider handleExceptionProvider
387+
*/
388+
public function testHandleException(string $expectedMessage, \Throwable $exception)
386389
{
387390
try {
388391
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
389392
$handler = ErrorHandler::register();
390393

391-
$exception = new \Exception('foo');
392-
393-
$logArgCheck = function ($level, $message, $context) {
394-
$this->assertSame('Uncaught Exception: foo', $message);
394+
$logArgCheck = function ($level, $message, $context) use ($expectedMessage, $exception) {
395+
$this->assertSame($expectedMessage, $message);
395396
$this->assertArrayHasKey('exception', $context);
396-
$this->assertInstanceOf(\Exception::class, $context['exception']);
397+
$this->assertInstanceOf(\get_class($exception), $context['exception']);
397398
};
398399

399400
$logger
@@ -407,7 +408,7 @@ public function testHandleException()
407408
try {
408409
$handler->handleException($exception);
409410
$this->fail('Exception expected');
410-
} catch (\Exception $e) {
411+
} catch (\Throwable $e) {
411412
$this->assertSame($exception, $e);
412413
}
413414

@@ -422,6 +423,15 @@ public function testHandleException()
422423
}
423424
}
424425

426+
public function handleExceptionProvider(): array
427+
{
428+
return [
429+
['Uncaught Exception: foo', new \Exception('foo')],
430+
['Uncaught Error: bar', new \Error('bar')],
431+
['Uncaught ccc', new \ErrorException('ccc')],
432+
];
433+
}
434+
425435
public function testBootstrappingLogger()
426436
{
427437
$bootLogger = new BufferingLogger();
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\ErrorHandler;
13+
14+
/**
15+
* @internal
16+
*/
17+
class ThrowableUtils
18+
{
19+
public static function getSeverity(\Throwable $throwable): int
20+
{
21+
if ($throwable instanceof \ErrorException) {
22+
return $throwable->getSeverity();
23+
}
24+
25+
if ($throwable instanceof \ParseError) {
26+
return E_PARSE;
27+
}
28+
29+
if ($throwable instanceof \TypeError) {
30+
return E_RECOVERABLE_ERROR;
31+
}
32+
33+
return E_ERROR;
34+
}
35+
}

src/Symfony/Component/HttpKernel/EventListener/DebugHandlersListener.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Symfony\Component\Console\Event\ConsoleEvent;
1717
use Symfony\Component\Console\Output\ConsoleOutputInterface;
1818
use Symfony\Component\ErrorHandler\ErrorHandler;
19+
use Symfony\Component\ErrorHandler\Exception\FatalThrowableError;
1920
use Symfony\Component\EventDispatcher\Event;
2021
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
2122
use Symfony\Component\HttpKernel\Debug\FileLinkFormatter;
@@ -42,7 +43,7 @@ class DebugHandlersListener implements EventSubscriberInterface
4243
private $hasTerminatedWithException;
4344

4445
/**
45-
* @param callable|null $exceptionHandler A handler that will be called on Exception
46+
* @param callable|null $exceptionHandler A handler that must support \Throwable instances that will be called on Exception
4647
* @param array|int $levels An array map of E_* to LogLevel::* or an integer bit field of E_* constants
4748
* @param int|null $throwAt Thrown errors in a bit field of E_* constants, or null to keep the current value
4849
* @param bool $scream Enables/disables screaming mode, where even silenced errors are logged
@@ -106,10 +107,15 @@ public function configure(Event $event = null)
106107
if (method_exists($kernel = $event->getKernel(), 'terminateWithException')) {
107108
$request = $event->getRequest();
108109
$hasRun = &$this->hasTerminatedWithException;
109-
$this->exceptionHandler = static function (\Exception $e) use ($kernel, $request, &$hasRun) {
110+
$this->exceptionHandler = static function (\Throwable $e) use ($kernel, $request, &$hasRun) {
110111
if ($hasRun) {
111112
throw $e;
112113
}
114+
115+
if (!$e instanceof \Exception) {
116+
$e = new FatalThrowableError($e);
117+
}
118+
113119
$hasRun = true;
114120
$kernel->terminateWithException($e, $request);
115121
};

0 commit comments

Comments
 (0)
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