跳到内容

如何延迟加载命令

编辑此页

注意

如果您正在使用 Symfony 全栈框架,您可能正在查找关于 创建惰性命令 的详细信息

向您的应用添加命令的传统方法是使用 add(),它需要一个 Command 实例作为参数。

这种方法可能存在缺点,因为某些命令的实例化成本可能很高,在这种情况下,您可能希望延迟加载它们。 但请注意,延迟加载并非绝对的。 实际上,诸如 listhelp_complete 之类的少数命令可能需要实例化其他命令,即使它们是延迟加载的。 例如,list 需要获取所有命令的名称和描述,这可能需要实例化命令才能获取。

为了延迟加载命令,您需要注册一个中间加载器,它将负责返回 Command 实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
use App\Command\HeavyCommand;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\CommandLoader\FactoryCommandLoader;

$commandLoader = new FactoryCommandLoader([
    // Note that the `list` command will still instantiate that command
    // in this example.
    'app:heavy' => static fn(): Command => new HeavyCommand(),
]);

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

这样,HeavyCommand 实例将仅在实际调用 app:heavy 命令时创建。

此示例使用了内置的 FactoryCommandLoader 类,但是 setCommandLoader() 方法接受任何 CommandLoaderInterface 实例,因此您可以使用自己的实现。

另一种方法是利用 Symfony\Component\Console\Command\LazyCommand

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
use App\Command\HeavyCommand;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\CommandLoader\FactoryCommandLoader;

// In this case although the command is instantiated, the underlying command factory
// will not be executed unless the command is actually executed or one tries to access
// its input definition to know its argument or option inputs.
$lazyCommand = new LazyCommand(
    'app:heavy',
    [],
    'This is another more complete form of lazy command.',
    false,
    static fn (): Command => new HeavyCommand(),
);

$application = new Application();
$application->add($lazyCommand);
$application->run();

内置命令加载器

FactoryCommandLoader

FactoryCommandLoader 类提供了一种延迟加载命令的方法,因为它接受一个 Command 工厂数组作为其唯一的构造函数参数

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

$commandLoader = new FactoryCommandLoader([
    'app:foo' => function (): Command { return new FooCommand(); },
    'app:bar' => [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, [
    'app:foo' => FooCommand::class,
]);

像这样,执行 app:foo 命令将通过调用 $container->get(FooCommand::class) 来加载 FooCommand 服务。

这项工作,包括代码示例,根据 Creative Commons BY-SA 3.0 许可获得许可。
目录
    版本