-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
Description
Description
Currently a command is a single PHP class, which implements both: its definition and the code to execute it. This is perfectly fine for most use cases, but has downsides for more complicated ones.
For commands that implement business logic and makes heavy use of dependency injection, creating the command object can be very expensive.
This fact was greatly mitigated by introducing \Symfony\Component\Console\CommandLoader\CommandLoaderInterface
. Using that, will lazily instantiate only the command object specified, not all command objects like before.
However we still face this performance impact when listing all commands (console list
), where again all command objects are built "just" to show their names and the description (access the definition).
Therefore I'd propose to optionally separate definition from execution, by allowing commands to implement an interface which could roughly look like (don't pick on the names or details it's just an outline):
<?php
namespace Symfony\Component\Console\Command;
interface CommandDefinitionInterface
{
/**
* @return CommandDefinition Includes InputDefinition, name, description, help...
*/
public function getDefinition(): CommandDefinition;
/**
* Could also be part of CommandDefinition instead
*
* @return string Class name or service name, which implements CommandExecutorInterface or is closure
*/
public function getExecutor(): string;
}
interface CommandExecutorInterface
{
/**
* Executes command logic.
*
* @return int|null null or 0 if everything went fine, or an error code
*/
public function execute(InputInterface $input, OutputInterface $output);
}
The benefit of this (compared to setCode
, which could be deprecated then) is, that ContainerCommandLoader
could be made responsible for creating the executor instead of the command object having to have a dependency to a DI container.
Any thoughts? Thanks!