Skip to content

[Console] Distinguish definition of a command from its execution #33804

@helhum

Description

@helhum

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!

Metadata

Metadata

Assignees

No one assigned

    Labels

    ConsoleRFCRFC = Request For Comments (proposals about features that you want to be discussed)

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions