diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index 108c1ab20b839..fd12aa0981c6d 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -62,6 +62,7 @@ class Application private $name; private $version; private $catchExceptions = true; + private $catchErrors = false; private $autoExit = true; private $definition; private $helperSet; @@ -100,8 +101,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 +123,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 FatalThrowableError($e); + } + if (isset($e)) { if ($output instanceof ConsoleOutputInterface) { $this->renderException($e, $output->getErrorOutput()); } else { @@ -271,6 +277,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. * @@ -814,8 +836,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/Tests/ApplicationTest.php b/src/Symfony/Component/Console/Tests/ApplicationTest.php index 38b333a1770fa..8fbc49ab3399d 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 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' + [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.'); + } + public function testRunWithDispatcherSkippingCommand() { $application = new Application();