[Debug+VarDumper] Fix handling of PHP7 exception/error model

This commit is contained in:
Nicolas Grekas 2015-06-12 10:49:54 +02:00
parent edf793ead2
commit 4dc727fa7d
4 changed files with 53 additions and 41 deletions

View File

@ -14,8 +14,8 @@ namespace Symfony\Component\Debug;
use Psr\Log\LogLevel; use Psr\Log\LogLevel;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Symfony\Component\Debug\Exception\ContextErrorException; use Symfony\Component\Debug\Exception\ContextErrorException;
use Symfony\Component\Debug\Exception\FatalBaseException;
use Symfony\Component\Debug\Exception\FatalErrorException; use Symfony\Component\Debug\Exception\FatalErrorException;
use Symfony\Component\Debug\Exception\FatalThrowableError;
use Symfony\Component\Debug\Exception\OutOfMemoryException; use Symfony\Component\Debug\Exception\OutOfMemoryException;
use Symfony\Component\Debug\FatalErrorHandler\UndefinedFunctionFatalErrorHandler; use Symfony\Component\Debug\FatalErrorHandler\UndefinedFunctionFatalErrorHandler;
use Symfony\Component\Debug\FatalErrorHandler\UndefinedMethodFatalErrorHandler; use Symfony\Component\Debug\FatalErrorHandler\UndefinedMethodFatalErrorHandler;
@ -431,7 +431,7 @@ class ErrorHandler
/** /**
* Handles an exception by logging then forwarding it to an other handler. * Handles an exception by logging then forwarding it to an other handler.
* *
* @param \Exception|\BaseException $exception An exception to handle * @param \Exception|\Throwable $exception An exception to handle
* @param array $error An array as returned by error_get_last() * @param array $error An array as returned by error_get_last()
* *
* @internal * @internal
@ -439,7 +439,7 @@ class ErrorHandler
public function handleException($exception, array $error = null) public function handleException($exception, array $error = null)
{ {
if (!$exception instanceof \Exception) { if (!$exception instanceof \Exception) {
$exception = new FatalBaseException($exception); $exception = new FatalThrowableError($exception);
} }
$type = $exception instanceof FatalErrorException ? $exception->getSeverity() : E_ERROR; $type = $exception instanceof FatalErrorException ? $exception->getSeverity() : E_ERROR;
@ -451,15 +451,17 @@ class ErrorHandler
'level' => error_reporting(), 'level' => error_reporting(),
'stack' => $exception->getTrace(), 'stack' => $exception->getTrace(),
); );
if ($exception instanceof FatalBaseException) { if ($exception instanceof FatalErrorException) {
if ($exception instanceof FatalThrowableError) {
$error = array( $error = array(
'type' => $type, 'type' => $type,
'message' => $message = $exception->getMessage(), 'message' => $message = $exception->getMessage(),
'file' => $e['file'], 'file' => $e['file'],
'line' => $e['line'], 'line' => $e['line'],
); );
} elseif ($exception instanceof FatalErrorException) { } else {
$message = 'Fatal '.$exception->getMessage(); $message = 'Fatal '.$exception->getMessage();
}
} elseif ($exception instanceof \ErrorException) { } elseif ($exception instanceof \ErrorException) {
$message = 'Uncaught '.$exception->getMessage(); $message = 'Uncaught '.$exception->getMessage();
if ($exception instanceof ContextErrorException) { if ($exception instanceof ContextErrorException) {
@ -486,9 +488,9 @@ class ErrorHandler
try { try {
call_user_func($this->exceptionHandler, $exception); call_user_func($this->exceptionHandler, $exception);
} catch (\Exception $handlerException) { } catch (\Exception $handlerException) {
$this->exceptionHandler = null; } catch (\Throwable $handlerException) {
$this->handleException($handlerException); }
} catch (\BaseException $handlerException) { if (isset($handlerException)) {
$this->exceptionHandler = null; $this->exceptionHandler = null;
$this->handleException($handlerException); $this->handleException($handlerException);
} }

View File

@ -12,18 +12,18 @@
namespace Symfony\Component\Debug\Exception; namespace Symfony\Component\Debug\Exception;
/** /**
* Base Fatal Error Exception. * Fatal Throwable Error.
* *
* @author Nicolas Grekas <p@tchwork.com> * @author Nicolas Grekas <p@tchwork.com>
*/ */
class FatalBaseException extends FatalErrorException class FatalThrowableError extends FatalErrorException
{ {
public function __construct(\BaseException $e) public function __construct(\Throwable $e)
{ {
if ($e instanceof \ParseException) { if ($e instanceof \ParseError) {
$message = 'Parse error: '.$e->getMessage(); $message = 'Parse error: '.$e->getMessage();
$severity = E_PARSE; $severity = E_PARSE;
} elseif ($e instanceof \TypeException) { } elseif ($e instanceof \TypeError) {
$message = 'Type error: '.$e->getMessage(); $message = 'Type error: '.$e->getMessage();
$severity = E_RECOVERABLE_ERROR; $severity = E_RECOVERABLE_ERROR;
} else { } else {

View File

@ -40,27 +40,14 @@ class ExceptionCaster
E_STRICT => 'E_STRICT', E_STRICT => 'E_STRICT',
); );
public static function castError(\Error $e, array $a, Stub $stub, $isNested)
{
return $e instanceof \Exception ? $a : self::filterExceptionArray($a, "\0Error\0");
}
public static function castException(\Exception $e, array $a, Stub $stub, $isNested) public static function castException(\Exception $e, array $a, Stub $stub, $isNested)
{ {
$xPrefix = PHP_VERSION_ID >= 70000 ? "\0BaseException\0" : "\0Exception\0"; return self::filterExceptionArray($a, "\0Exception\0");
if (isset($a[$xPrefix.'trace'])) {
$trace = $a[$xPrefix.'trace'];
unset($a[$xPrefix.'trace']); // Ensures the trace is always last
} else {
$trace = array();
}
static::filterTrace($trace, static::$traceArgs);
if (null !== $trace) {
$a[$xPrefix.'trace'] = $trace;
}
if (empty($a[$xPrefix.'previous'])) {
unset($a[$xPrefix.'previous']);
}
unset($a[$xPrefix.'string'], $a["\0+\0xdebug_message"], $a["\0+\0__destructorException"]);
return $a;
} }
public static function castErrorException(\ErrorException $e, array $a, Stub $stub, $isNested) public static function castErrorException(\ErrorException $e, array $a, Stub $stub, $isNested)
@ -75,7 +62,7 @@ class ExceptionCaster
public static function castThrowingCasterException(ThrowingCasterException $e, array $a, Stub $stub, $isNested) public static function castThrowingCasterException(ThrowingCasterException $e, array $a, Stub $stub, $isNested)
{ {
$prefix = "\0*\0"; $prefix = "\0*\0";
$xPrefix = PHP_VERSION_ID >= 70000 ? "\0BaseException\0" : "\0Exception\0"; $xPrefix = "\0Exception\0";
if (isset($a[$xPrefix.'previous'], $a[$xPrefix.'trace'][0])) { if (isset($a[$xPrefix.'previous'], $a[$xPrefix.'trace'][0])) {
$b = (array) $a[$xPrefix.'previous']; $b = (array) $a[$xPrefix.'previous'];
@ -123,4 +110,26 @@ class ExceptionCaster
} }
} }
} }
private static function filterExceptionArray(array $a, $xPrefix)
{
if (isset($a[$xPrefix.'trace'])) {
$trace = $a[$xPrefix.'trace'];
unset($a[$xPrefix.'trace']); // Ensures the trace is always last
} else {
$trace = array();
}
static::filterTrace($trace, static::$traceArgs);
if (null !== $trace) {
$a[$xPrefix.'trace'] = $trace;
}
if (empty($a[$xPrefix.'previous'])) {
unset($a[$xPrefix.'previous']);
}
unset($a[$xPrefix.'string'], $a["\0+\0xdebug_message"], $a["\0+\0__destructorException"]);
return $a;
}
} }

View File

@ -57,6 +57,7 @@ abstract class AbstractCloner implements ClonerInterface
'ErrorException' => 'Symfony\Component\VarDumper\Caster\ExceptionCaster::castErrorException', 'ErrorException' => 'Symfony\Component\VarDumper\Caster\ExceptionCaster::castErrorException',
'Exception' => 'Symfony\Component\VarDumper\Caster\ExceptionCaster::castException', 'Exception' => 'Symfony\Component\VarDumper\Caster\ExceptionCaster::castException',
'Error' => 'Symfony\Component\VarDumper\Caster\ExceptionCaster::castError',
'Symfony\Component\DependencyInjection\ContainerInterface' => 'Symfony\Component\VarDumper\Caster\StubCaster::cutInternals', 'Symfony\Component\DependencyInjection\ContainerInterface' => 'Symfony\Component\VarDumper\Caster\StubCaster::cutInternals',
'Symfony\Component\VarDumper\Exception\ThrowingCasterException' => 'Symfony\Component\VarDumper\Caster\ExceptionCaster::castThrowingCasterException', 'Symfony\Component\VarDumper\Exception\ThrowingCasterException' => 'Symfony\Component\VarDumper\Caster\ExceptionCaster::castThrowingCasterException',