public function command($expression, $callable, array $aliases = [])
    {
        $this->assertCallableIsValid($callable);

        $commandFunction = function (InputInterface $input, OutputInterface $output) use ($callable) {
            $parameters = array_merge(
                [
                    // Injection by parameter name
                    'input' => $input,
                    'output' => $output,
                    // Injections by type-hint
                    InputInterface::class => $input,
                    OutputInterface::class => $output,
                    Input::class => $input,
                    Output::class => $output,
                    SymfonyStyle::class => new SymfonyStyle($input, $output),
                ],
                // Arguments and options are injected by parameter names
                $input->getArguments(),
                $input->getOptions()
            );

            if ($callable instanceof \Closure) {
                $callable = $callable->bindTo($this, $this);
            }

            try {
                return $this->invoker->call($callable, $parameters);
            } catch (InvocationException $e) {
                throw new \RuntimeException(sprintf(
                    "Impossible to call the '%s' command: %s",
                    $input->getFirstArgument(),
                    $e->getMessage()
                ), 0, $e);
            }
        };

        $command = $this->createCommand($expression, $commandFunction);
        $command->setAliases($aliases);

        $command->defaults($this->defaultsViaReflection($command, $callable));

        $this->add($command);

        return $command;
    }