From 64f9856a2fc3740bfcd17d3a3de17ac8400a42bd Mon Sep 17 00:00:00 2001 From: Maxime STEINHAUSSER Date: Wed, 7 Dec 2016 09:44:01 +0100 Subject: [PATCH 1/2] [Console] Allow Application to handle PHP 7 Errors --- UPGRADE-4.0.md | 4 +++ src/Symfony/Component/Console/Application.php | 33 ++++++++++++++++--- .../Console/Exception/ErrorException.php | 26 +++++++++++++++ .../Console/Tests/ApplicationTest.php | 33 +++++++++++++++++++ 4 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 src/Symfony/Component/Console/Exception/ErrorException.php diff --git a/UPGRADE-4.0.md b/UPGRADE-4.0.md index 483b7e6ed1447..aeb7522985f67 100644 --- a/UPGRADE-4.0.md +++ b/UPGRADE-4.0.md @@ -6,6 +6,10 @@ Console * Setting unknown style options is not supported anymore and throws an exception. + + * The signature of `Application::renderException(\Exception $e, OutputInterface $output)` + has changed for `Application::renderException(\Throwable $e, OutputInterface $output)`. + You must update your implementations. Debug ----- diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index 108c1ab20b839..dd2254516927a 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Console; +use Symfony\Component\Console\Exception\ErrorException; use Symfony\Component\Console\Exception\ExceptionInterface; use Symfony\Component\Console\Helper\DebugFormatterHelper; use Symfony\Component\Console\Helper\ProcessHelper; @@ -62,6 +63,7 @@ class Application private $name; private $version; private $catchExceptions = true; + private $catchErrors = false; private $autoExit = true; private $definition; private $helperSet; @@ -100,8 +102,6 @@ public function setDispatcher(EventDispatcherInterface $dispatcher) * @param OutputInterface $output An Output instance * * @return int 0 if everything went fine, or an error code - * - * @throws \Exception When doRun returns Exception */ public function run(InputInterface $input = null, OutputInterface $output = null) { @@ -124,7 +124,14 @@ public function run(InputInterface $input = null, OutputInterface $output = null if (!$this->catchExceptions) { throw $e; } + } catch (\Error $e) { + if (!$this->catchErrors) { + throw $e; + } + $e = new ErrorException($e); + } + if (isset($e)) { if ($output instanceof ConsoleOutputInterface) { $this->renderException($e, $output->getErrorOutput()); } else { @@ -271,6 +278,22 @@ public function setCatchExceptions($boolean) $this->catchExceptions = (bool) $boolean; } + /** + * @return bool Whether errors are caught or not during commands execution + */ + public function areErrorsCaught() + { + return $this->catchErrors; + } + + /** + * @param bool $boolean Whether to catch errors or not during commands execution + */ + public function setCatchErrors($boolean) + { + $this->catchErrors = (bool) $boolean; + } + /** * Gets whether to automatically exit after a command execution or not. * @@ -620,6 +643,10 @@ public static function getAbbreviations($names) */ public function renderException(\Exception $e, OutputInterface $output) { + if ($e instanceof ErrorException) { + $e = $e->getError(); + } + $output->writeln('', OutputInterface::VERBOSITY_QUIET); do { @@ -814,8 +841,6 @@ protected function configureIO(InputInterface $input, OutputInterface $output) * @param OutputInterface $output An Output instance * * @return int 0 if everything went fine, or an error code - * - * @throws \Exception when the command being run threw an exception */ protected function doRunCommand(Command $command, InputInterface $input, OutputInterface $output) { diff --git a/src/Symfony/Component/Console/Exception/ErrorException.php b/src/Symfony/Component/Console/Exception/ErrorException.php new file mode 100644 index 0000000000000..de8828dc106dd --- /dev/null +++ b/src/Symfony/Component/Console/Exception/ErrorException.php @@ -0,0 +1,26 @@ +error = $error; + } + + /** + * @return \Error + */ + public function getError() + { + return $this->error; + } +} diff --git a/src/Symfony/Component/Console/Tests/ApplicationTest.php b/src/Symfony/Component/Console/Tests/ApplicationTest.php index 38b333a1770fa..3233dd154aa1a 100644 --- a/src/Symfony/Component/Console/Tests/ApplicationTest.php +++ b/src/Symfony/Component/Console/Tests/ApplicationTest.php @@ -1000,6 +1000,39 @@ public function testRunWithErrorFailingStatusCode() $this->assertSame(1, $tester->getStatusCode(), 'Status code should be 1'); } + public function testErrorsAreNotCaughtByDefault() + { + $application = new Application(); + + $this->assertFalse($application->areErrorsCaught()); + } + + /** + * @requires PHP 7 + */ + public function testCatchesErrors() + { + $application = new Application(); + + $application->setCatchErrors(true); + $application->setAutoExit(false); + + $this->assertTrue($application->areErrorsCaught()); + + $application->register('foo')->setCode(function () { + throw new \Error('This error should be catch by Application::run'); + }); + + $tester = new ApplicationTester($application); + $tester->run(array('command' => 'foo')); + $this->assertSame(1, $tester->getStatusCode(), 'Status code should be 1'); + $this->assertContains(<<<'EOTXT' + [Error] + This error should be catch by Application::run +EOTXT + , $tester->getDisplay(true), 'The PHP error should be caught when catchErrors is true.'); + } + public function testRunWithDispatcherSkippingCommand() { $application = new Application(); From 11bd59661d06ad37b7a96ac4212d7cabad3b0c5c Mon Sep 17 00:00:00 2001 From: Maxime Steinhausser Date: Wed, 14 Dec 2016 21:25:26 +0100 Subject: [PATCH 2/2] Use FatalThrowableError --- UPGRADE-4.0.md | 4 --- src/Symfony/Component/Console/Application.php | 7 +---- .../Console/Exception/ErrorException.php | 26 ------------------- .../Console/Tests/ApplicationTest.php | 6 ++--- 4 files changed, 4 insertions(+), 39 deletions(-) delete mode 100644 src/Symfony/Component/Console/Exception/ErrorException.php diff --git a/UPGRADE-4.0.md b/UPGRADE-4.0.md index aeb7522985f67..483b7e6ed1447 100644 --- a/UPGRADE-4.0.md +++ b/UPGRADE-4.0.md @@ -6,10 +6,6 @@ Console * Setting unknown style options is not supported anymore and throws an exception. - - * The signature of `Application::renderException(\Exception $e, OutputInterface $output)` - has changed for `Application::renderException(\Throwable $e, OutputInterface $output)`. - You must update your implementations. Debug ----- diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index dd2254516927a..fd12aa0981c6d 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -11,7 +11,6 @@ namespace Symfony\Component\Console; -use Symfony\Component\Console\Exception\ErrorException; use Symfony\Component\Console\Exception\ExceptionInterface; use Symfony\Component\Console\Helper\DebugFormatterHelper; use Symfony\Component\Console\Helper\ProcessHelper; @@ -128,7 +127,7 @@ public function run(InputInterface $input = null, OutputInterface $output = null if (!$this->catchErrors) { throw $e; } - $e = new ErrorException($e); + $e = new FatalThrowableError($e); } if (isset($e)) { @@ -643,10 +642,6 @@ public static function getAbbreviations($names) */ public function renderException(\Exception $e, OutputInterface $output) { - if ($e instanceof ErrorException) { - $e = $e->getError(); - } - $output->writeln('', OutputInterface::VERBOSITY_QUIET); do { diff --git a/src/Symfony/Component/Console/Exception/ErrorException.php b/src/Symfony/Component/Console/Exception/ErrorException.php deleted file mode 100644 index de8828dc106dd..0000000000000 --- a/src/Symfony/Component/Console/Exception/ErrorException.php +++ /dev/null @@ -1,26 +0,0 @@ -error = $error; - } - - /** - * @return \Error - */ - public function getError() - { - return $this->error; - } -} diff --git a/src/Symfony/Component/Console/Tests/ApplicationTest.php b/src/Symfony/Component/Console/Tests/ApplicationTest.php index 3233dd154aa1a..8fbc49ab3399d 100644 --- a/src/Symfony/Component/Console/Tests/ApplicationTest.php +++ b/src/Symfony/Component/Console/Tests/ApplicationTest.php @@ -1020,15 +1020,15 @@ public function testCatchesErrors() $this->assertTrue($application->areErrorsCaught()); $application->register('foo')->setCode(function () { - throw new \Error('This error should be catch by Application::run'); + throw new \Error('This error should be caught by Application::run'); }); $tester = new ApplicationTester($application); $tester->run(array('command' => 'foo')); $this->assertSame(1, $tester->getStatusCode(), 'Status code should be 1'); $this->assertContains(<<<'EOTXT' - [Error] - This error should be catch by Application::run + [Symfony\Component\Debug\Exception\FatalThrowableError] + This error should be caught by Application::run EOTXT , $tester->getDisplay(true), 'The PHP error should be caught when catchErrors is true.'); }