How to Make Commands Lazily Loaded
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;
$container = new ContainerBuilder();
$container->register(FooCommand::class, FooCommand::class);
$container->compile();
$commandLoader = new ContainerCommandLoader($container, [
'app:foo' => FooCommand::class,
]);
Like this, executing the app:foo
command will load the FooCommand
service
by calling $container->get(FooCommand::class)
.