Как сделать команды ленивой загрузки

Как сделать команды ленивой загрузки

Note

Если вы используете полностековый фреймворк Symfony, то вы скорее всего ищете подробности о создании команд ленивой загрузки

Традиционный способ добавления команд в ваше приложение - это использование add(), который ожидает экземпляр Command в качестве аргумента.

Для того, чтобы лениво загружать команды, вам нужно зарегистрировать срединный загрузчик, который будет отвечать за возвращение экземпляров Command:

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(array(
    'app:heavy' => function () { return new HeavyCommand() },
));

$application = new Application();
$application->setCommandLoader($commandLoader);
$application->run();

Таким образом, экземпляр HeavyCommand будет создан только тогда, когда команда app:heavy будет действительно вызвана.

Этот пример использует встроенный класс FactoryCommandLoader, но метод setCommandLoader() принимает любой экземпляр CommandLoaderInterface, так что вы можете использовать собственные реализации.

Встроенные загрузчики команд

FactoryCommandLoader

Класс FactoryCommandLoader предоставляет простой способ получения команд ленивой загрузки, так как он берёт массив фабрик Command в качестве единственного аргумента конструктора:

1
2
3
4
5
6
use Symfony\Component\Console\CommandLoader\FactoryCommandLoader;

$commandLoader = new FactoryCommandLoader(array(
    'app:foo' => function () { return new FooCommand() },
    'app:bar' => array(BarCommand::class, 'create'),
));

Фабрики могут быть любым PHP вызываемым и будут выполнены каждый раз, когда вызывается get().

ContainerCommandLoader

Класс ContainerCommandLoader может быть использован для загрузки команды из контейнера PSR-11. Таким образом, её конструктор берёт реализацию PSR-11 ContainerInterface в качестве своего первого аргумента, а карту команды - в качестве последнего. Карта команды должна быть массивом с именами команд в качестве ключей и идентификаторами сервисов в качестве значений:

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, array(
    'app:foo' => FooCommand::class,
));

Таким образом, выполнение команды app:foo загрузит сервис FooCommand, вызвав $container->get(FooCommand::class).