diff --git a/src/Symfony/Component/Console/Command/Command.php b/src/Symfony/Component/Console/Command/Command.php index 1d2e12bdcce2..d8f6d7358029 100644 --- a/src/Symfony/Component/Console/Command/Command.php +++ b/src/Symfony/Component/Console/Command/Command.php @@ -356,6 +356,14 @@ public function complete(CompletionInput $input, CompletionSuggestions $suggesti } } + /** + * Get the code that is executed by the command. + */ + public function getCode(): ?callable + { + return $this->code?->getCode(); + } + /** * Sets the code to execute when running this command. * diff --git a/src/Symfony/Component/Console/Command/InvokableCommand.php b/src/Symfony/Component/Console/Command/InvokableCommand.php index 72ff407c81fd..b497f4df73bf 100644 --- a/src/Symfony/Component/Console/Command/InvokableCommand.php +++ b/src/Symfony/Component/Console/Command/InvokableCommand.php @@ -30,18 +30,20 @@ */ class InvokableCommand implements SignalableCommandInterface { - private readonly \Closure $code; + private readonly \Closure $closure; private readonly ?SignalableCommandInterface $signalableCommand; private readonly \ReflectionFunction $reflection; private bool $triggerDeprecations = false; + private $code; public function __construct( private readonly Command $command, callable $code, ) { - $this->code = $this->getClosure($code); + $this->code = $code; + $this->closure = $this->getClosure($code); $this->signalableCommand = $code instanceof SignalableCommandInterface ? $code : null; - $this->reflection = new \ReflectionFunction($this->code); + $this->reflection = new \ReflectionFunction($this->closure); } /** @@ -49,7 +51,7 @@ public function __construct( */ public function __invoke(InputInterface $input, OutputInterface $output): int { - $statusCode = ($this->code)(...$this->getParameters($input, $output)); + $statusCode = ($this->closure)(...$this->getParameters($input, $output)); if (!\is_int($statusCode)) { if ($this->triggerDeprecations) { @@ -81,6 +83,11 @@ public function configure(InputDefinition $definition): void } } + public function getCode(): callable + { + return $this->code; + } + private function getClosure(callable $code): \Closure { if (!$code instanceof \Closure) { diff --git a/src/Symfony/Component/Console/Tests/Command/CommandTest.php b/src/Symfony/Component/Console/Tests/Command/CommandTest.php index a4a719b3d10a..fd7755ca381c 100644 --- a/src/Symfony/Component/Console/Tests/Command/CommandTest.php +++ b/src/Symfony/Component/Console/Tests/Command/CommandTest.php @@ -469,6 +469,8 @@ public function testCommandAttribute() $this->assertStringContainsString('usage1', $command->getUsages()[0]); $this->assertTrue($command->isHidden()); $this->assertSame(['f'], $command->getAliases()); + // Standard commands don't have code. + $this->assertNull($command->getCode()); } /** diff --git a/src/Symfony/Component/Console/Tests/Command/InvokableCommandTest.php b/src/Symfony/Component/Console/Tests/Command/InvokableCommandTest.php index 8bd0dceb4425..f7b947db3358 100644 --- a/src/Symfony/Component/Console/Tests/Command/InvokableCommandTest.php +++ b/src/Symfony/Component/Console/Tests/Command/InvokableCommandTest.php @@ -26,6 +26,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\NullOutput; use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Tests\Fixtures\InvokableTestCommand; class InvokableCommandTest extends TestCase { @@ -292,6 +293,15 @@ public function __invoke() $command->run(new ArrayInput([]), new NullOutput()); } + public function testGetCode() + { + // Create a command from an invokable class. + $command = new Command(null, new InvokableTestCommand()); + + // Ensure that the invokable class can be retrieved from the Command. + $this->assertInstanceOf(InvokableTestCommand::class, $command->getCode()); + } + /** * @dataProvider provideInputArguments */