Skip to content

Commit c8db006

Browse files
committed
[ErrorHandler] Forward \Throwable
1 parent 11fab74 commit c8db006

File tree

7 files changed

+92
-47
lines changed

7 files changed

+92
-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;
@@ -236,7 +235,7 @@ public function setLoggers(array $loggers): array
236235

237236
if ($flush) {
238237
foreach ($this->bootstrappingLogger->cleanLogs() as $log) {
239-
$type = $log[2]['exception'] instanceof \ErrorException ? $log[2]['exception']->getSeverity() : E_ERROR;
238+
$type = $log[2]['exception'] instanceof \ErrorException ? $log[2]['exception']->getSeverity() : ThrowableUtils::getSeverity($log[2]['exception']);
240239
if (!isset($flush[$type])) {
241240
$this->bootstrappingLogger->log($log[0], $log[1], $log[2]);
242241
} elseif ($this->loggers[$type][0]) {
@@ -251,7 +250,7 @@ public function setLoggers(array $loggers): array
251250
/**
252251
* Sets a user exception handler.
253252
*
254-
* @param callable|null $handler A handler that will be called on Exception
253+
* @param callable|null $handler A handler that must support \Throwable instances that will be called on Exception
255254
*
256255
* @return callable|null The previous exception handler
257256
*/
@@ -510,57 +509,64 @@ public function handleError(int $type, string $message, string $file, int $line)
510509
/**
511510
* Handles an exception by logging then forwarding it to another handler.
512511
*
513-
* @param \Exception|\Throwable $exception An exception to handle
514-
* @param array $error An array as returned by error_get_last()
512+
* @param array $error An array as returned by error_get_last()
515513
*
516514
* @internal
517515
*/
518-
public function handleException($exception, array $error = null)
516+
public function handleException(\Throwable $exception, array $error = null)
519517
{
520518
if (null === $error) {
521519
self::$exitCode = 255;
522520
}
523-
if (!$exception instanceof \Exception) {
524-
$exception = new FatalThrowableError($exception);
525-
}
526-
$type = $exception instanceof FatalErrorException ? $exception->getSeverity() : E_ERROR;
521+
522+
$type = $exception instanceof FatalErrorException ? $exception->getSeverity() : ThrowableUtils::getSeverity($exception);
527523
$handlerException = null;
528524

529-
if (($this->loggedErrors & $type) || $exception instanceof FatalThrowableError) {
525+
if (($this->loggedErrors & $type) || $exception instanceof \Error) {
530526
if (false !== strpos($message = $exception->getMessage(), "class@anonymous\0")) {
531527
$message = $this->parseAnonymousClass($message);
532528
}
529+
533530
if ($exception instanceof FatalErrorException) {
534-
if ($exception instanceof FatalThrowableError) {
535-
$error = [
536-
'type' => $type,
537-
'message' => $message,
538-
'file' => $exception->getFile(),
539-
'line' => $exception->getLine(),
540-
];
541-
} else {
542-
$message = 'Fatal '.$message;
543-
}
531+
$message = 'Fatal '.$message;
544532
} elseif ($exception instanceof \ErrorException) {
545533
$message = 'Uncaught '.$message;
534+
} elseif ($exception instanceof \Error) {
535+
$error = [
536+
'type' => $type,
537+
'message' => $message,
538+
'file' => $exception->getFile(),
539+
'line' => $exception->getLine(),
540+
];
541+
$message = 'Uncaught Error: '.$message;
546542
} else {
547543
$message = 'Uncaught Exception: '.$message;
548544
}
549545
}
546+
550547
if ($this->loggedErrors & $type) {
551548
try {
552549
$this->loggers[$type][0]->log($this->loggers[$type][1], $message, ['exception' => $exception]);
553550
} catch (\Throwable $handlerException) {
554551
}
555552
}
553+
554+
// temporary until fatal error handlers rework
555+
$originalException = $exception;
556+
if (!$exception instanceof \Exception) {
557+
$exception = new FatalErrorException($exception->getMessage(), $exception->getCode(), $type, $exception->getFile(), $exception->getLine(), null, true, $exception->getTrace());
558+
}
559+
556560
if ($exception instanceof FatalErrorException && !$exception instanceof OutOfMemoryException && $error) {
557561
foreach ($this->getFatalErrorHandlers() as $handler) {
558562
if ($e = $handler->handleError($error, $exception)) {
559-
$exception = $e;
563+
$convertedException = $e;
560564
break;
561565
}
562566
}
563567
}
568+
569+
$exception = $convertedException ?? $originalException;
564570
$exceptionHandler = $this->exceptionHandler;
565571
$this->exceptionHandler = null;
566572
try {

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
@@ -331,18 +331,19 @@ public function testHandleDeprecation()
331331
restore_error_handler();
332332
}
333333

334-
public function testHandleException()
334+
/**
335+
* @dataProvider handleExceptionProvider
336+
*/
337+
public function testHandleExceptiossssn(string $expectedMessage, \Throwable $exception)
335338
{
336339
try {
337340
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
338341
$handler = ErrorHandler::register();
339342

340-
$exception = new \Exception('foo');
341-
342-
$logArgCheck = function ($level, $message, $context) {
343-
$this->assertSame('Uncaught Exception: foo', $message);
343+
$logArgCheck = function ($level, $message, $context) use ($expectedMessage, $exception) {
344+
$this->assertSame($expectedMessage, $message);
344345
$this->assertArrayHasKey('exception', $context);
345-
$this->assertInstanceOf(\Exception::class, $context['exception']);
346+
$this->assertInstanceOf(\get_class($exception), $context['exception']);
346347
};
347348

348349
$logger
@@ -356,7 +357,7 @@ public function testHandleException()
356357
try {
357358
$handler->handleException($exception);
358359
$this->fail('Exception expected');
359-
} catch (\Exception $e) {
360+
} catch (\Throwable $e) {
360361
$this->assertSame($exception, $e);
361362
}
362363

@@ -371,6 +372,15 @@ public function testHandleException()
371372
}
372373
}
373374

375+
public function handleExceptionProvider(): array
376+
{
377+
return [
378+
['Uncaught Exception: foo', new \Exception('foo')],
379+
['Uncaught Error: bar', new \Error('bar')],
380+
['Uncaught ccc', new \ErrorException('ccc')],
381+
];
382+
}
383+
374384
public function testBootstrappingLogger()
375385
{
376386
$bootLogger = new BufferingLogger();
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
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 \ParseError) {
22+
return E_PARSE;
23+
} elseif ($throwable instanceof \TypeError) {
24+
return E_RECOVERABLE_ERROR;
25+
}
26+
27+
return E_ERROR;
28+
}
29+
}

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\ErrorRenderer\ErrorRenderer;
2021
use Symfony\Component\ErrorRenderer\ErrorRenderer\HtmlErrorRenderer;
2122
use Symfony\Component\ErrorRenderer\Exception\ErrorRendererNotFoundException;
@@ -50,7 +51,7 @@ class DebugHandlersListener implements EventSubscriberInterface
5051
private $hasTerminatedWithException;
5152

5253
/**
53-
* @param callable|null $exceptionHandler A handler that will be called on Exception
54+
* @param callable|null $exceptionHandler A handler that must support \Throwable instances that will be called on Exception
5455
* @param array|int $levels An array map of E_* to LogLevel::* or an integer bit field of E_* constants
5556
* @param int|null $throwAt Thrown errors in a bit field of E_* constants, or null to keep the current value
5657
* @param bool $scream Enables/disables screaming mode, where even silenced errors are logged
@@ -116,10 +117,15 @@ public function configure(Event $event = null)
116117
if (method_exists($kernel = $event->getKernel(), 'terminateWithException')) {
117118
$request = $event->getRequest();
118119
$hasRun = &$this->hasTerminatedWithException;
119-
$this->exceptionHandler = static function (\Exception $e) use ($kernel, $request, &$hasRun) {
120+
$this->exceptionHandler = static function (\Throwable $e) use ($kernel, $request, &$hasRun) {
120121
if ($hasRun) {
121122
throw $e;
122123
}
124+
125+
if (!$e instanceof \Exception) {
126+
$e = new FatalThrowableError($e);
127+
}
128+
123129
$hasRun = true;
124130
$kernel->terminateWithException($e, $request);
125131
};

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