Skip to content

[Console] Ensure overriding Command::execute() keeps priority over __invoke() #60361

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Symfony/Component/Console/Command/Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,8 @@
$this->setHelp($attribute?->help ?? '');
}

if (\is_callable($this)) {
if (\is_callable($this) && (new \ReflectionMethod($this, 'execute'))->getDeclaringClass()->name === self::class) {
$this->code = new InvokableCommand($this, $this(...));

Check failure on line 138 in src/Symfony/Component/Console/Command/Command.php

View workflow job for this annotation

GitHub Actions / Psalm

NoValue

src/Symfony/Component/Console/Command/Command.php:138:48: NoValue: All possible types for this argument were invalidated - This may be dead code (see https://psalm.dev/179)

Check failure on line 138 in src/Symfony/Component/Console/Command/Command.php

View workflow job for this annotation

GitHub Actions / Psalm

NoValue

src/Symfony/Component/Console/Command/Command.php:138:48: NoValue: All possible types for this argument were invalidated - This may be dead code (see https://psalm.dev/179)
}

$this->configure();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
use Symfony\Component\Console\Exception\InvalidOptionException;
use Symfony\Component\Console\Exception\LogicException;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\NullOutput;
use Symfony\Component\Console\Output\OutputInterface;

class InvokableCommandTest extends TestCase
{
Expand Down Expand Up @@ -142,6 +144,45 @@ public function testInvalidOptionType()
$command->getDefinition();
}

public function testExecuteHasPriorityOverInvokeMethod()
{
$command = new class extends Command {
public string $called;
protected function execute(InputInterface $input, OutputInterface $output): int
{
$this->called = __FUNCTION__;

return 0;
}

public function __invoke(): int
{
$this->called = __FUNCTION__;

return 0;
}
};

$command->run(new ArrayInput([]), new NullOutput());
$this->assertSame('execute', $command->called);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This tests only if it was called, but in theory the other method could be called before

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only it was the last called. I assumed that was enough to cover the feature.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But priority means it should be the first called method, right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In practice, only one of them can be called by Command::run()

}

public function testCallInvokeMethodWhenExtendingCommandClass()
{
$command = new class extends Command {
public string $called;
public function __invoke(): int
{
$this->called = __FUNCTION__;

return 0;
}
};

$command->run(new ArrayInput([]), new NullOutput());
$this->assertSame('__invoke', $command->called);
}

public function testInvalidReturnType()
{
$command = new Command('foo');
Expand Down
Loading