diff --git a/src/Symfony/Component/HttpKernel/Debug/ErrorHandler.php b/src/Symfony/Component/HttpKernel/Debug/ErrorHandler.php index 605c08626c..197ec03cf3 100644 --- a/src/Symfony/Component/HttpKernel/Debug/ErrorHandler.php +++ b/src/Symfony/Component/HttpKernel/Debug/ErrorHandler.php @@ -11,6 +11,8 @@ namespace Symfony\Component\HttpKernel\Debug; +use Symfony\Component\HttpKernel\Exception\FatalErrorException; + /** * ErrorHandler. * @@ -28,10 +30,16 @@ class ErrorHandler E_RECOVERABLE_ERROR => 'Catchable Fatal Error', E_DEPRECATED => 'Deprecated', E_USER_DEPRECATED => 'User Deprecated', + E_ERROR => 'Error', + E_CORE_ERROR => 'Core Error', + E_COMPILE_ERROR => 'Compile Error', + E_PARSE => 'Parse', ); private $level; + private $reservedMemory; + /** * Register the error handler. * @@ -45,6 +53,8 @@ class ErrorHandler $handler->setLevel($level); set_error_handler(array($handler, 'handle')); + register_shutdown_function(array($handler, 'handleFatal')); + $handler->reservedMemory = str_repeat('x', 10240); return $handler; } @@ -69,4 +79,28 @@ class ErrorHandler return false; } + + public function handleFatal() + { + if (null === $error = error_get_last()) { + return; + } + + unset($this->reservedMemory); + $type = $error['type']; + if (0 === $this->level || !in_array($type, array(E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE))) { + return; + } + + // get current exception handler + $exceptionHandler = set_exception_handler(function() {}); + restore_exception_handler(); + + if (is_array($exceptionHandler) && $exceptionHandler[0] instanceof ExceptionHandler) { + $level = isset($this->levels[$type]) ? $this->levels[$type] : $type; + $message = sprintf('%s: %s in %s line %d', $level, $error['message'], $error['file'], $error['line']); + $exception = new FatalErrorException($message, 0, $type, $error['file'], $error['line']); + $exceptionHandler[0]->handle($exception); + } + } } diff --git a/src/Symfony/Component/HttpKernel/Debug/ExceptionHandler.php b/src/Symfony/Component/HttpKernel/Debug/ExceptionHandler.php index 88ef3d7615..79d7d66dcc 100644 --- a/src/Symfony/Component/HttpKernel/Debug/ExceptionHandler.php +++ b/src/Symfony/Component/HttpKernel/Debug/ExceptionHandler.php @@ -234,6 +234,9 @@ EOF; img { border: 0; } #sf-resetcontent { width:970px; margin:0 auto; } $css + .xdebug-error { + display: none; + } diff --git a/src/Symfony/Component/HttpKernel/Exception/FatalErrorException.php b/src/Symfony/Component/HttpKernel/Exception/FatalErrorException.php new file mode 100644 index 0000000000..a082f80dc0 --- /dev/null +++ b/src/Symfony/Component/HttpKernel/Exception/FatalErrorException.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Exception; + +/** + * Fatal Error Exception. + * + * @author Konstanton Myakshin + */ +class FatalErrorException extends \ErrorException +{ + +} diff --git a/src/Symfony/Component/HttpKernel/Exception/FlattenException.php b/src/Symfony/Component/HttpKernel/Exception/FlattenException.php index eb5e5715fa..367b549440 100644 --- a/src/Symfony/Component/HttpKernel/Exception/FlattenException.php +++ b/src/Symfony/Component/HttpKernel/Exception/FlattenException.php @@ -47,7 +47,7 @@ class FlattenException $e->setStatusCode($statusCode); $e->setHeaders($headers); - $e->setTrace($exception->getTrace(), $exception->getFile(), $exception->getLine()); + $e->setTraceFromException($exception); $e->setClass(get_class($exception)); $e->setFile($exception->getFile()); $e->setLine($exception->getLine()); @@ -168,6 +168,40 @@ class FlattenException return $this->trace; } + public function setTraceFromException(\Exception $exception) + { + $trace = $exception->getTrace(); + + if ($exception instanceof FatalErrorException) { + if (function_exists('xdebug_get_function_stack')) { + $trace = array_slice(array_reverse(xdebug_get_function_stack()), 4); + + foreach ($trace as $i => $frame) { + // XDebug pre 2.1.1 doesn't currently set the call type key http://bugs.xdebug.org/view.php?id=695 + if (!isset($frame['type'])) { + $trace[$i]['type'] = '??'; + } + + if ('dynamic' === $trace[$i]['type']) { + $trace[$i]['type'] = '->'; + } elseif ('static' === $trace[$i]['type']) { + $trace[$i]['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']); + } + } + } else { + $trace = array_slice(array_reverse($trace), 1); + } + } + + $this->setTrace($trace, $exception->getFile(), $exception->getLine()); + } + public function setTrace($trace, $file, $line) { $this->trace = array(); diff --git a/src/Symfony/Component/HttpKernel/Tests/Debug/ErrorHandlerTest.php b/src/Symfony/Component/HttpKernel/Tests/Debug/ErrorHandlerTest.php index 0eb2d79d4c..e98d326a4b 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Debug/ErrorHandlerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Debug/ErrorHandlerTest.php @@ -12,7 +12,6 @@ namespace Symfony\Component\HttpKernel\Tests\Debug; use Symfony\Component\HttpKernel\Debug\ErrorHandler; -use Symfony\Component\HttpKernel\Debug\ErrorException; /** * ErrorHandlerTest @@ -48,10 +47,10 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase $handler = ErrorHandler::register(3); try { - $handler->handle(1, 'foo', 'foo.php', 12, 'foo'); + $handler->handle(111, 'foo', 'foo.php', 12, 'foo'); } catch (\ErrorException $e) { - $this->assertSame('1: foo in foo.php line 12', $e->getMessage()); - $this->assertSame(1, $e->getSeverity()); + $this->assertSame('111: foo in foo.php line 12', $e->getMessage()); + $this->assertSame(111, $e->getSeverity()); $this->assertSame('foo.php', $e->getFile()); $this->assertSame(12, $e->getLine()); } diff --git a/src/Symfony/Component/HttpKernel/Tests/Exception/FlattenExceptionTest.php b/src/Symfony/Component/HttpKernel/Tests/Exception/FlattenExceptionTest.php index 934b44b461..d51ab6aa07 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Exception/FlattenExceptionTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Exception/FlattenExceptionTest.php @@ -156,14 +156,14 @@ class FlattenExceptionTest extends \PHPUnit_Framework_TestCase public function testToArray(\Exception $exception, $statusCode) { $flattened = FlattenException::create($exception); - $flattened->setTrace(array(),'foo.php',123); + $flattened->setTrace(array(), 'foo.php', 123); $this->assertEquals(array( array( 'message'=> 'test', 'class'=>'Exception', 'trace'=>array(array( - 'namespace' => '', 'short_class' => '', 'class' => '','type' => '','function' => '', 'file' => 'foo.php','line' => 123, + 'namespace' => '', 'short_class' => '', 'class' => '','type' => '','function' => '', 'file' => 'foo.php', 'line' => 123, 'args' => array() )), )