feature #12330 [Debug] DI controllable ErrorHandler::register() (nicolas-grekas)

This PR was merged into the 2.6-dev branch.

Discussion
----------

[Debug] DI controllable ErrorHandler::register()

| Q             | A
| ------------- | ---
| Bug fix?      | yes
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | yes
| Tests pass?   | yes
| Fixed tickets | #12327
| License       | MIT
| Doc PR        | -

This enhances the `ErrorHandler::register()` signature in a BC way, allowing greater control.

See https://github.com/symfony/symfony/pull/12330/files?w=1

Commits
-------

417f021 [Debug] DI controllable ErrorHandler::register()
This commit is contained in:
Fabien Potencier 2014-11-02 02:14:41 +01:00
commit 0588f0e8fb
3 changed files with 63 additions and 27 deletions

View File

@ -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);

View File

@ -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 {
$handler->setExceptionHandler(set_exception_handler(array($handler, 'handleException')));
$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();
}
$handler->throwAt($throw ? $levels : 0, true);
$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($levels & $handler->thrownErrors, true);
return $handler;
}

View File

@ -52,12 +52,28 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
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 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
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 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
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 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
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 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
->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 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
->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 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
}
}
public function testDeprecated()
public function testDeprecatedInterface()
{
try {
$handler = ErrorHandler::register(0);