Skip to content

Commit

Permalink
[Debug][ErrorHandler] Preserve next error handler
Browse files Browse the repository at this point in the history
Co-authored-by: Joe <cuchac@email.cz>
  • Loading branch information
fancyweb and cuchac committed Feb 16, 2019
1 parent 37b0eeb commit a8b3434
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 15 deletions.
7 changes: 6 additions & 1 deletion src/Symfony/Component/Debug/ErrorHandler.php
Expand Up @@ -517,6 +517,11 @@ public function handleError($type, $message, $file, $line)
$errorAsException ? ['exception' => $errorAsException] : [],
];
} else {
if (!\defined('HHVM_VERSION')) {
$currentErrorHandler = set_error_handler('var_dump');
restore_error_handler();
}

try {
$this->isRecursive = true;
$level = ($type & $level) ? $this->loggers[$type][1] : LogLevel::DEBUG;
Expand All @@ -525,7 +530,7 @@ public function handleError($type, $message, $file, $line)
$this->isRecursive = false;

if (!\defined('HHVM_VERSION')) {
set_error_handler([$this, __FUNCTION__]);
set_error_handler($currentErrorHandler);
}
}
}
Expand Down
39 changes: 27 additions & 12 deletions src/Symfony/Component/Debug/Tests/ErrorHandlerTest.php
Expand Up @@ -12,12 +12,12 @@
namespace Symfony\Component\Debug\Tests;

use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
use Psr\Log\NullLogger;
use Symfony\Component\Debug\BufferingLogger;
use Symfony\Component\Debug\ErrorHandler;
use Symfony\Component\Debug\Exception\SilencedErrorContext;
use Symfony\Component\Debug\Tests\Fixtures\ErrorHandlerThatUsesThePreviousOne;
use Symfony\Component\Debug\Tests\Fixtures\LoggerThatSetAnErrorHandler;

/**
Expand Down Expand Up @@ -590,26 +590,40 @@ public function testCustomExceptionHandler()
}

/**
* @dataProvider errorHandlerIsNotLostWhenLoggingProvider
* @dataProvider errorHandlerWhenLoggingProvider
*/
public function testErrorHandlerIsNotLostWhenLogging($customErrorHandlerHasBeenPreviouslyDefined, LoggerInterface $logger)
public function testErrorHandlerWhenLogging($previousHandlerWasDefined, $loggerSetsAnotherHandler, $nextHandlerIsDefined)
{
try {
if ($customErrorHandlerHasBeenPreviouslyDefined) {
if ($previousHandlerWasDefined) {
set_error_handler('count');
}

$logger = $loggerSetsAnotherHandler ? new LoggerThatSetAnErrorHandler() : new NullLogger();

$handler = ErrorHandler::register();
$handler->setDefaultLogger($logger);

if ($nextHandlerIsDefined) {
$handler = ErrorHandlerThatUsesThePreviousOne::register();
}

@trigger_error('foo', E_USER_DEPRECATED);
@trigger_error('bar', E_USER_DEPRECATED);

$this->assertSame([$handler, 'handleError'], set_error_handler('var_dump'));

if ($logger instanceof LoggerThatSetAnErrorHandler) {
$this->assertCount(2, $logger->cleanLogs());
}

restore_error_handler();

if ($customErrorHandlerHasBeenPreviouslyDefined) {
if ($previousHandlerWasDefined) {
restore_error_handler();
}

if ($nextHandlerIsDefined) {
restore_error_handler();
}
} finally {
Expand All @@ -618,13 +632,14 @@ public function testErrorHandlerIsNotLostWhenLogging($customErrorHandlerHasBeenP
}
}

public function errorHandlerIsNotLostWhenLoggingProvider()
public function errorHandlerWhenLoggingProvider()
{
return [
[false, new NullLogger()],
[true, new NullLogger()],
[false, new LoggerThatSetAnErrorHandler()],
[true, new LoggerThatSetAnErrorHandler()],
];
foreach ([false, true] as $previousHandlerWasDefined) {
foreach ([false, true] as $loggerSetsAnotherHandler) {
foreach ([false, true] as $nextHandlerIsDefined) {
yield [$previousHandlerWasDefined, $loggerSetsAnotherHandler, $nextHandlerIsDefined];
}
}
}
}
}
@@ -0,0 +1,22 @@
<?php

namespace Symfony\Component\Debug\Tests\Fixtures;

class ErrorHandlerThatUsesThePreviousOne
{
private static $previous;

public static function register()
{
$handler = new static();

self::$previous = set_error_handler([$handler, 'handleError']);

return $handler;
}

public function handleError($type, $message, $file, $line, $context)
{
return \call_user_func(self::$previous, $type, $message, $file, $line, $context);
}
}
Expand Up @@ -2,13 +2,14 @@

namespace Symfony\Component\Debug\Tests\Fixtures;

use Psr\Log\AbstractLogger;
use Symfony\Component\Debug\BufferingLogger;

class LoggerThatSetAnErrorHandler extends AbstractLogger
class LoggerThatSetAnErrorHandler extends BufferingLogger
{
public function log($level, $message, array $context = [])
{
set_error_handler('is_string');
parent::log($level, $message, $context);
restore_error_handler();
}
}

0 comments on commit a8b3434

Please sign in to comment.