How to Make Commands Lazily Loaded
Warning: You are browsing the documentation for Symfony 4.x, which is no longer maintained.
Read the updated version of this page for Symfony 7.1 (the current stable version).
Note
If you are using the Symfony full-stack framework, you are probably looking for details about creating lazy commands
The traditional way of adding commands to your application is to use
add(), which expects a
Command
instance as an argument.
In order to lazy-load commands, you need to register an intermediate loader
which will be responsible for returning Command
instances:
1 2 3 4 5 6 7 8 9 10 11
use App\Command\HeavyCommand;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\CommandLoader\FactoryCommandLoader;
$commandLoader = new FactoryCommandLoader([
'app:heavy' => function () { return new HeavyCommand(); },
]);
$application = new Application();
$application->setCommandLoader($commandLoader);
$application->run();
This way, the HeavyCommand
instance will be created only when the app:heavy
command is actually called.
This example makes use of the built-in FactoryCommandLoader class, but the setCommandLoader() method accepts any CommandLoaderInterface instance so you can use your own implementation.
Built-in Command Loaders
FactoryCommandLoader
The FactoryCommandLoader
class provides a way of getting commands lazily loaded as it takes an
array of Command
factories as its only constructor argument:
1 2 3 4 5 6
use Symfony\Component\Console\CommandLoader\FactoryCommandLoader;
$commandLoader = new FactoryCommandLoader([
'app:foo' => function () { return new FooCommand(); },
'app:bar' => [BarCommand::class, 'create'],
]);
Factories can be any PHP callable and will be executed each time get() is called.
ContainerCommandLoader
The ContainerCommandLoader
class can be used to load commands from a PSR-11 container. As such, its
constructor takes a PSR-11 ContainerInterface
implementation as its first
argument and a command map as its last argument. The command map must be an array
with command names as keys and service identifiers as values:
1 2 3 4 5 6 7 8 9 10
use Symfony\Component\Console\CommandLoader\ContainerCommandLoader;
use Symfony\Component\DependencyInjection\ContainerBuilder;
$containerBuilder = new ContainerBuilder();
$containerBuilder->register(FooCommand::class, FooCommand::class);
$containerBuilder->compile();
$commandLoader = new ContainerCommandLoader($containerBuilder, [
'app:foo' => FooCommand::class,
]);
Like this, executing the app:foo
command will load the FooCommand
service
by calling $containerBuilder->get(FooCommand::class)
.