From 417f021797896c4c29c788fb1de9f109e4c13255 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 27 Oct 2014 14:40:25 +0100 Subject: [PATCH] [Debug] DI controllable ErrorHandler::register() --- .../FrameworkBundle/FrameworkBundle.php | 2 +- src/Symfony/Component/Debug/ErrorHandler.php | 39 ++++++++++----- .../Debug/Tests/ErrorHandlerTest.php | 47 ++++++++++++++----- 3 files changed, 62 insertions(+), 26 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php index cb7d1e125b4b..10896786c9f0 100644 --- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php +++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php @@ -47,7 +47,7 @@ class FrameworkBundle extends Bundle { public function boot() { - ErrorHandler::register($this->container->getParameter('debug.error_handler.throw_at')); + ErrorHandler::register(null, false)->throwAt($this->container->getParameter('debug.error_handler.throw_at'), true); if ($trustedProxies = $this->container->getParameter('kernel.trusted_proxies')) { Request::setTrustedProxies($trustedProxies); diff --git a/src/Symfony/Component/Debug/ErrorHandler.php b/src/Symfony/Component/Debug/ErrorHandler.php index b1f36c48a452..f6c043287b17 100644 --- a/src/Symfony/Component/Debug/ErrorHandler.php +++ b/src/Symfony/Component/Debug/ErrorHandler.php @@ -110,29 +110,42 @@ class ErrorHandler /** * Registers the error handler. * - * @param int $levels Levels to register to for throwing, 0 for none - * @param bool $throw @deprecated argument, same as setting $levels to 0 + * @param self|null|int $handler The handler to register, or @deprecated (since 2.6, to be removed in 3.0) bit field of thrown levels + * @param bool $replace Whether to replace or not any existing handler * - * @return ErrorHandler The registered error handler + * @return self The registered error handler */ - public static function register($levels = -1, $throw = true) + public static function register($handler = null, $replace = true) { if (null === self::$reservedMemory) { self::$reservedMemory = str_repeat('x', 10240); register_shutdown_function(__CLASS__.'::handleFatalError'); } - $handler = new static(); - $levels &= $handler->thrownErrors; - $prev = set_error_handler(array($handler, 'handleError'), $levels); - $prev = is_array($prev) ? $prev[0] : null; - if ($prev instanceof self) { - restore_error_handler(); - $handler = $prev; - } else { + $levels = -1; + + if ($handlerIsNew = !$handler instanceof self) { + // @deprecated polymorphism, to be removed in 3.0 + if (null !== $handler) { + $levels = $replace ? $handler : 0; + $replace = true; + } + $handler = new static(); + } + + $prev = set_error_handler(array($handler, 'handleError'), $handler->thrownErrors | $handler->loggedErrors); + + if ($handlerIsNew && is_array($prev) && $prev[0] instanceof self) { + $handler = $prev[0]; + $replace = false; + } + if ($replace || !$prev) { $handler->setExceptionHandler(set_exception_handler(array($handler, 'handleException'))); + } else { + restore_error_handler(); } - $handler->throwAt($throw ? $levels : 0, true); + + $handler->throwAt($levels & $handler->thrownErrors, true); return $handler; } diff --git a/src/Symfony/Component/Debug/Tests/ErrorHandlerTest.php b/src/Symfony/Component/Debug/Tests/ErrorHandlerTest.php index 9ed596681397..97eb3d7a4e9a 100644 --- a/src/Symfony/Component/Debug/Tests/ErrorHandlerTest.php +++ b/src/Symfony/Component/Debug/Tests/ErrorHandlerTest.php @@ -52,12 +52,28 @@ public function testRegister() try { $this->assertInstanceOf('Symfony\Component\Debug\ErrorHandler', $handler); + $this->assertSame($handler, ErrorHandler::register()); + + $newHandler = new ErrorHandler(); + + $this->assertSame($newHandler, ErrorHandler::register($newHandler, false)); + $h = set_error_handler('var_dump'); + restore_error_handler(); + $this->assertSame(array($handler, 'handleError'), $h); try { - $this->assertSame($handler, ErrorHandler::register()); - } catch (\Exception $e) { + $this->assertSame($newHandler, ErrorHandler::register($newHandler, true)); + $h = set_error_handler('var_dump'); restore_error_handler(); - restore_exception_handler(); + $this->assertSame(array($newHandler, 'handleError'), $h); + } catch (\Exception $e) { + } + + restore_error_handler(); + restore_exception_handler(); + + if (isset($e)) { + throw $e; } } catch (\Exception $e) { } @@ -121,7 +137,9 @@ private static function triggerNotice($that) public function testConstruct() { try { - $this->assertEquals(3 | E_RECOVERABLE_ERROR | E_USER_ERROR, ErrorHandler::register(3)->throwAt(0)); + $handler = ErrorHandler::register(); + $handler->throwAt(3, true); + $this->assertEquals(3 | E_RECOVERABLE_ERROR | E_USER_ERROR, $handler->throwAt(0)); restore_error_handler(); restore_exception_handler(); @@ -175,19 +193,22 @@ public function testDefaultLogger() public function testHandleError() { try { - $handler = ErrorHandler::register(0); + $handler = ErrorHandler::register(); + $handler->throwAt(0, true); $this->assertFalse($handler->handleError(0, 'foo', 'foo.php', 12, array())); restore_error_handler(); restore_exception_handler(); - $handler = ErrorHandler::register(3); + $handler = ErrorHandler::register(); + $handler->throwAt(3, true); $this->assertFalse($handler->handleError(4, 'foo', 'foo.php', 12, array())); restore_error_handler(); restore_exception_handler(); - $handler = ErrorHandler::register(3); + $handler = ErrorHandler::register(); + $handler->throwAt(3, true); try { $handler->handleError(4, 'foo', 'foo.php', 12, array()); } catch (\ErrorException $e) { @@ -200,13 +221,15 @@ public function testHandleError() restore_error_handler(); restore_exception_handler(); - $handler = ErrorHandler::register(E_USER_DEPRECATED); + $handler = ErrorHandler::register(); + $handler->throwAt(E_USER_DEPRECATED, true); $this->assertFalse($handler->handleError(E_USER_DEPRECATED, 'foo', 'foo.php', 12, array())); restore_error_handler(); restore_exception_handler(); - $handler = ErrorHandler::register(E_DEPRECATED); + $handler = ErrorHandler::register(); + $handler->throwAt(E_DEPRECATED, true); $this->assertFalse($handler->handleError(E_DEPRECATED, 'foo', 'foo.php', 12, array())); restore_error_handler(); @@ -230,7 +253,7 @@ public function testHandleError() ->will($this->returnCallback($warnArgCheck)) ; - $handler = ErrorHandler::register(E_USER_DEPRECATED); + $handler = ErrorHandler::register(); $handler->setDefaultLogger($logger, E_USER_DEPRECATED); $this->assertTrue($handler->handleError(E_USER_DEPRECATED, 'foo', 'foo.php', 12, array())); @@ -252,7 +275,7 @@ public function testHandleError() ->will($this->returnCallback($logArgCheck)) ; - $handler = ErrorHandler::register(E_NOTICE); + $handler = ErrorHandler::register(); $handler->setDefaultLogger($logger, E_NOTICE); $handler->screamAt(E_NOTICE); unset($undefVar); @@ -357,7 +380,7 @@ public function testHandleFatalError() } } - public function testDeprecated() + public function testDeprecatedInterface() { try { $handler = ErrorHandler::register(0);