diff --git a/src/Symfony/Component/Debug/ErrorHandler.php b/src/Symfony/Component/Debug/ErrorHandler.php index 9a6f6fa1c3..850f7d9c55 100644 --- a/src/Symfony/Component/Debug/ErrorHandler.php +++ b/src/Symfony/Component/Debug/ErrorHandler.php @@ -15,6 +15,7 @@ use Psr\Log\LogLevel; use Psr\Log\LoggerInterface; use Symfony\Component\Debug\Exception\ContextErrorException; use Symfony\Component\Debug\Exception\FatalErrorException; +use Symfony\Component\Debug\Exception\OutOfMemoryException; use Symfony\Component\Debug\FatalErrorHandler\UndefinedFunctionFatalErrorHandler; use Symfony\Component\Debug\FatalErrorHandler\UndefinedMethodFatalErrorHandler; use Symfony\Component\Debug\FatalErrorHandler\ClassNotFoundFatalErrorHandler; @@ -313,12 +314,16 @@ class ErrorHandler $level = isset($this->levels[$error['type']]) ? $this->levels[$error['type']] : $error['type']; $message = sprintf('%s: %s in %s line %d', $level, $error['message'], $error['file'], $error['line']); - $exception = new FatalErrorException($message, 0, $error['type'], $error['file'], $error['line'], 3); + if (0 === strpos($error['message'], 'Allowed memory') || 0 === strpos($error['message'], 'Out of memory')) { + $exception = new OutOfMemoryException($message, 0, $error['type'], $error['file'], $error['line'], 3, false); + } else { + $exception = new FatalErrorException($message, 0, $error['type'], $error['file'], $error['line'], 3, true); - foreach ($this->getFatalErrorHandlers() as $handler) { - if ($e = $handler->handleError($error, $exception)) { - $exception = $e; - break; + foreach ($this->getFatalErrorHandlers() as $handler) { + if ($e = $handler->handleError($error, $exception)) { + $exception = $e; + break; + } } } diff --git a/src/Symfony/Component/Debug/Exception/FatalErrorException.php b/src/Symfony/Component/Debug/Exception/FatalErrorException.php index 4e29495f30..d5b58468c9 100644 --- a/src/Symfony/Component/Debug/Exception/FatalErrorException.php +++ b/src/Symfony/Component/Debug/Exception/FatalErrorException.php @@ -20,7 +20,7 @@ namespace Symfony\Component\Debug\Exception; */ class FatalErrorException extends \ErrorException { - public function __construct($message, $code, $severity, $filename, $lineno, $traceOffset = null) + public function __construct($message, $code, $severity, $filename, $lineno, $traceOffset = null, $traceArgs = true) { parent::__construct($message, $code, $severity, $filename, $lineno); @@ -28,28 +28,32 @@ class FatalErrorException extends \ErrorException if (function_exists('xdebug_get_function_stack')) { $trace = xdebug_get_function_stack(); if (0 < $traceOffset) { - $trace = array_slice($trace, 0, -$traceOffset); + array_splice($trace, -$traceOffset); } - $trace = array_reverse($trace); - foreach ($trace as $i => $frame) { + foreach ($trace as &$frame) { if (!isset($frame['type'])) { // XDebug pre 2.1.1 doesn't currently set the call type key http://bugs.xdebug.org/view.php?id=695 if (isset($frame['class'])) { - $trace[$i]['type'] = '::'; + $frame['type'] = '::'; } } elseif ('dynamic' === $frame['type']) { - $trace[$i]['type'] = '->'; + $frame['type'] = '->'; } elseif ('static' === $frame['type']) { - $trace[$i]['type'] = '::'; + $frame['type'] = '::'; } // XDebug also has a different name for the parameters array - if (isset($frame['params']) && !isset($frame['args'])) { - $trace[$i]['args'] = $frame['params']; - unset($trace[$i]['params']); + if (!$traceArgs) { + unset($frame['params'], $frame['args']); + } elseif (isset($frame['params']) && !isset($frame['args'])) { + $frame['args'] = $frame['params']; + unset($frame['params']); } } + + unset($frame); + $trace = array_reverse($trace); } else { $trace = array(); } diff --git a/src/Symfony/Component/Debug/Exception/OutOfMemoryException.php b/src/Symfony/Component/Debug/Exception/OutOfMemoryException.php new file mode 100644 index 0000000000..fec1979836 --- /dev/null +++ b/src/Symfony/Component/Debug/Exception/OutOfMemoryException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Debug\Exception; + +/** + * Out of memory exception. + * + * @author Nicolas Grekas + */ +class OutOfMemoryException extends FatalErrorException +{ +} diff --git a/src/Symfony/Component/Debug/ExceptionHandler.php b/src/Symfony/Component/Debug/ExceptionHandler.php index 4979899afc..bfbd78313f 100644 --- a/src/Symfony/Component/Debug/ExceptionHandler.php +++ b/src/Symfony/Component/Debug/ExceptionHandler.php @@ -13,6 +13,7 @@ namespace Symfony\Component\Debug; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Debug\Exception\FlattenException; +use Symfony\Component\Debug\Exception\OutOfMemoryException; if (!defined('ENT_SUBSTITUTE')) { define('ENT_SUBSTITUTE', 8); @@ -62,6 +63,8 @@ class ExceptionHandler * Sets a user exception handler. * * @param callable $handler An handler that will be called on Exception + * + * @return callable|null The previous exception handler if any */ public function setHandler($handler) { @@ -88,6 +91,12 @@ class ExceptionHandler */ public function handle(\Exception $exception) { + if ($exception instanceof OutOfMemoryException) { + $this->sendPhpResponse($exception); + + return; + } + // To be as fail-safe as possible, the exception is first handled // by our simple exception handler, then by the user exception handler. // The latter takes precedence and any output from the former is cancelled,