Skip to content

[ErrorCatcher][ExceptionHandler] Handle \Throwable #31694

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
[Debug] Make ExceptionHandler and ErrorHandler final
  • Loading branch information
fancyweb committed Jun 28, 2019
commit 64d02cb350c41ca4dba924a598eb55cbf3ce166c
7 changes: 6 additions & 1 deletion src/Symfony/Component/ErrorCatcher/ExceptionHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace Symfony\Component\ErrorCatcher;

use Symfony\Component\ErrorCatcher\ErrorRenderer\HtmlErrorRenderer;
use Symfony\Component\ErrorCatcher\Exception\FatalThrowableError;
use Symfony\Component\ErrorCatcher\Exception\FlattenException;
use Symfony\Component\ErrorCatcher\Exception\OutOfMemoryException;
use Symfony\Component\HttpKernel\Debug\FileLinkFormatter;
Expand Down Expand Up @@ -101,8 +102,12 @@ public function setHandler(callable $handler = null)
* The latter takes precedence and any output from the former is cancelled,
* if and only if nothing bad happens in this handling path.
*/
public function handle(\Exception $exception)
public function handle(\Throwable $exception)
{
if (!$exception instanceof \Exception) {
$exception = new FatalThrowableError($exception);
}

if (null === $this->handler || $exception instanceof OutOfMemoryException) {
$this->sendPhpResponse($exception);

Expand Down
79 changes: 60 additions & 19 deletions src/Symfony/Component/ErrorCatcher/Tests/ExceptionHandlerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public function testHeaders()

ob_start();
$handler->sendPhpResponse(new MethodNotAllowedHttpException(['POST']));
$response = ob_get_clean();
ob_get_clean();

$expectedHeaders = [
['HTTP/1.0 405', true, null],
Expand All @@ -106,37 +106,78 @@ public function testNestedExceptions()
$this->assertStringMatchesFormat('%A<p class="break-long-words trace-message">Foo</p>%A<p class="break-long-words trace-message">Bar</p>%A', $response);
}

public function testHandle()
/**
* @dataProvider handleProvider
*/
public function testHandle(\Throwable $exception, string $expectedClass, string $expectedTitle, string $expectedMessage)
{
$exception = new \Exception('foo');

$handler = $this->getMockBuilder('Symfony\Component\ErrorCatcher\ExceptionHandler')->setMethods(['sendPhpResponse'])->getMock();
$handler
->expects($this->exactly(2))
->method('sendPhpResponse');
$handler = new ExceptionHandler(true);
ob_start();

$handler->handle($exception);

$handler->setHandler(function ($e) use ($exception) {
$this->assertSame($exception, $e);
$this->assertThatTheExceptionWasOutput(ob_get_clean(), $expectedClass, $expectedTitle, $expectedMessage);
}

public function handleProvider()
{
return [
[new \Exception('foo'), \Exception::class, 'Exception', 'foo'],
[new \Error('bar'), \Error::class, 'Error', 'bar'],
];
}

public function testHandleWithACustomHandlerThatOutputsSomething()
{
$handler = new ExceptionHandler(true);
ob_start();
$handler->setHandler(function () {
echo 'ccc';
});

$handler->handle($exception);
$handler->handle(new \Exception());
ob_end_flush(); // Necessary because of this PHP bug : https://bugs.php.net/bug.php?id=76563
$this->assertSame('ccc', ob_get_clean());
}

public function testHandleOutOfMemoryException()
public function testHandleWithACustomHandlerThatOutputsNothing()
{
$handler = new ExceptionHandler(true);
$handler->setHandler(function () {});

$handler->handle(new \Exception('ccc'));

$this->assertThatTheExceptionWasOutput(ob_get_clean(), \Exception::class, 'Exception', 'ccc');
}

public function testHandleWithACustomHandlerThatFails()
{
$exception = new OutOfMemoryException('foo', 0, E_ERROR, __FILE__, __LINE__);
$handler = new ExceptionHandler(true);
$handler->setHandler(function () {
throw new \RuntimeException();
});

$handler->handle(new \Exception('ccc'));

$handler = $this->getMockBuilder('Symfony\Component\ErrorCatcher\ExceptionHandler')->setMethods(['sendPhpResponse'])->getMock();
$handler
->expects($this->once())
->method('sendPhpResponse');
$this->assertThatTheExceptionWasOutput(ob_get_clean(), \Exception::class, 'Exception', 'ccc');
}

$handler->setHandler(function ($e) {
public function testHandleOutOfMemoryException()
{
$handler = new ExceptionHandler(true);
ob_start();
$handler->setHandler(function () {
$this->fail('OutOfMemoryException should bypass the handler');
});

$handler->handle($exception);
$handler->handle(new OutOfMemoryException('foo', 0, E_ERROR, __FILE__, __LINE__));

$this->assertThatTheExceptionWasOutput(ob_get_clean(), OutOfMemoryException::class, 'OutOfMemoryException', 'foo');
}

private function assertThatTheExceptionWasOutput(string $content, string $expectedClass, string $expectedTitle, string $expectedMessage)
{
$this->assertContains(sprintf('<span class="exception_title"><abbr title="%s">%s</abbr></span>', $expectedClass, $expectedTitle), $content);
$this->assertContains(sprintf('<h1 class="break-long-words exception-message">%s</h1>', $expectedMessage), $content);
}
}
24 changes: 0 additions & 24 deletions src/Symfony/Component/ErrorCatcher/Tests/MockExceptionHandler.php

This file was deleted.