Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Console] Refactor the Console component for lazy-loading of commands #12063

Closed
@mnapoli

Description

@mnapoli

Commands have to be instantiated to be registered in the console application:

$application = new Application();
$application->add(new GreetCommand);

That's a problem, for example if you have commands with big dependency graphs: it loads all the dependencies in memory. It's also not very practical when using Symfony\Console outside of the framework: integrating it with a DI container is not practical.

I would like to discuss a new way to register commands which would allow them to be lazy loaded. That requires to have the definition of their names outside of the command itself (else the lazy loading is useless).

To do this, there are several options.

1. Closures

The first one would be to leave the opportunity to provide a callable that returns the command:

$commandFactory = function () {
    return new GreetCommand();
}

$application = new Application();
$application->add($commandFactory, 'greet');

That option is BC compatible, but not that good for DX, not very practical.

2. CommandResolver

This is inspired by how HttpKernel works.

$application = new Application();
// Classic command
$application->addCommand('greet', array('Acme\AcmeDemoBundle\Command\GreetCommand', 'execute'));
// Invokable class (i.e. implements __invoke())
$application->addCommand('greet', 'Acme\AcmeDemoBundle\Command\GreetCommand');

// first parameter: the command name
// second parameter: a way to identify the command (string or array)

The HttpKernel uses a ControllerResolver to create controllers. The Console component could have a CommandResolverInterface:

interface CommandResolverInterface
{
    /**
     * @param string|array $command
     * @return callable|false A PHP callable representing the Command,
     *                        or false if this resolver is not able to determine the command
     */
    public function getCommand($command);
}

That would leave the option to implement this interface using any DI container.

That option could be made BC compatible. However it requires more work and it's a big change in the component.


I would really favor the second solution (or something similar). I've read the discussions about that topic, I know opinions are diverse.

I just want to emphasize that I don't want to make Symfony\Console too similar to HttpKernel. Some have suggested that in the past (me included), and I know this won't happen. I am not suggesting to merge Request and Input for example. I am just suggesting to separate the command routing from the command creation, just like it is in HttpKernel.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions