From 3806983bc2ec3747141ad3cb1dff1e2aec2e9382 Mon Sep 17 00:00:00 2001 From: sunxyw Date: Sat, 17 Dec 2022 21:53:08 +0800 Subject: [PATCH 1/2] change commands definition to attribute --- src/ZM/Command/BotCraft/BotCraftCommand.php | 16 ++++++-------- src/ZM/Command/BuildCommand.php | 6 ++---- src/ZM/Command/CheckConfigCommand.php | 9 ++------ .../Generate/SystemdGenerateCommand.php | 10 ++------- src/ZM/Command/InitCommand.php | 6 ++---- src/ZM/Command/ProxyServerCommand.php | 8 +++---- src/ZM/Command/ReplCommand.php | 21 +++++++------------ src/ZM/Command/Server/ServerReloadCommand.php | 9 ++------ src/ZM/Command/Server/ServerStartCommand.php | 10 ++++----- src/ZM/Command/Server/ServerStatusCommand.php | 9 ++------ src/ZM/Command/Server/ServerStopCommand.php | 5 ++--- 11 files changed, 36 insertions(+), 73 deletions(-) diff --git a/src/ZM/Command/BotCraft/BotCraftCommand.php b/src/ZM/Command/BotCraft/BotCraftCommand.php index b9333fe7..66ef103b 100644 --- a/src/ZM/Command/BotCraft/BotCraftCommand.php +++ b/src/ZM/Command/BotCraft/BotCraftCommand.php @@ -4,19 +4,15 @@ declare(strict_types=1); namespace ZM\Command\BotCraft; -use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Attribute\AsCommand; +use ZM\Command\Command; -/** - * TODO: 用于从命令行创建插件 - */ +#[AsCommand(name: 'bc:make', description: '生成插件')] class BotCraftCommand extends Command { - protected static $defaultName = 'bc:make'; - - public function execute(InputInterface $input, OutputInterface $output) + protected function handle(): int { - return 0; + // TODO: Implement handle() method. + return self::SUCCESS; } } diff --git a/src/ZM/Command/BuildCommand.php b/src/ZM/Command/BuildCommand.php index 35886738..4728171c 100644 --- a/src/ZM/Command/BuildCommand.php +++ b/src/ZM/Command/BuildCommand.php @@ -4,22 +4,20 @@ declare(strict_types=1); namespace ZM\Command; +use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; +#[AsCommand(name: 'build', description: '将项目构建一个phar包')] class BuildCommand extends Command { - // the name of the command (the part after "bin/console") - protected static $defaultName = 'build'; - /** * 配置 */ protected function configure() { - $this->setDescription('Build an ".phar" file | 将项目构建一个phar包'); $this->setHelp('此功能将会把整个项目打包为phar'); $this->addOption('target', 'D', InputOption::VALUE_REQUIRED, 'Output Directory | 指定输出目录'); // ... diff --git a/src/ZM/Command/CheckConfigCommand.php b/src/ZM/Command/CheckConfigCommand.php index eaec01e2..5534e60b 100644 --- a/src/ZM/Command/CheckConfigCommand.php +++ b/src/ZM/Command/CheckConfigCommand.php @@ -4,21 +4,16 @@ declare(strict_types=1); namespace ZM\Command; +use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; +#[AsCommand(name: 'check:config', description: '检查配置文件是否和框架当前版本有更新')] class CheckConfigCommand extends Command { - protected static $defaultName = 'check:config'; - private $need_update = false; - protected function configure() - { - $this->setDescription('检查配置文件是否和框架当前版本有更新'); - } - protected function execute(InputInterface $input, OutputInterface $output): int { if (LOAD_MODE !== 1) { diff --git a/src/ZM/Command/Generate/SystemdGenerateCommand.php b/src/ZM/Command/Generate/SystemdGenerateCommand.php index 851f9ca1..f8b2c235 100644 --- a/src/ZM/Command/Generate/SystemdGenerateCommand.php +++ b/src/ZM/Command/Generate/SystemdGenerateCommand.php @@ -4,20 +4,14 @@ declare(strict_types=1); namespace ZM\Command\Generate; +use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; +#[AsCommand(name: 'generate:systemd', description: '生成systemd配置文件')] class SystemdGenerateCommand extends Command { - // the name of the command (the part after "bin/console") - protected static $defaultName = 'generate:systemd'; - - protected function configure() - { - $this->setDescription('生成框架的 systemd 配置文件'); - } - protected function execute(InputInterface $input, OutputInterface $output): int { config()->addConfigPath(SOURCE_ROOT_DIR . '/config'); diff --git a/src/ZM/Command/InitCommand.php b/src/ZM/Command/InitCommand.php index e841eea4..b45997da 100644 --- a/src/ZM/Command/InitCommand.php +++ b/src/ZM/Command/InitCommand.php @@ -4,23 +4,21 @@ declare(strict_types=1); namespace ZM\Command; +use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\ConsoleSectionOutput; use Symfony\Component\Console\Output\OutputInterface; use ZM\Exception\InitException; +#[AsCommand(name: 'init', description: '初始化框架运行的基础文件')] class InitCommand extends Command { - // the name of the command (the part after "bin/console") - protected static $defaultName = 'init'; - private string $base_path; private bool $force = false; protected function configure(): void { - $this->setDescription('初始化框架运行的基础文件'); $this->setDefinition([ new InputOption('force', 'f', InputOption::VALUE_NONE, '覆盖现有文件'), new InputOption('docker', null, InputOption::VALUE_NONE, '启用 Docker 支持'), diff --git a/src/ZM/Command/ProxyServerCommand.php b/src/ZM/Command/ProxyServerCommand.php index c9fafcad..d869fff4 100644 --- a/src/ZM/Command/ProxyServerCommand.php +++ b/src/ZM/Command/ProxyServerCommand.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace ZM\Command; use OneBot\Driver\Workerman\Worker; +use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; @@ -14,11 +15,9 @@ use Workerman\Connection\AsyncUdpConnection; use Workerman\Timer; use ZM\Logger\ConsoleLogger; +#[AsCommand(name: 'proxy', description: '开启一个 HTTP 代理服务器')] class ProxyServerCommand extends Command { - // the name of the command (the part after "bin/console") - protected static $defaultName = 'proxy'; - private array $config = []; public function onSocksMessage($connection, $buffer) @@ -394,14 +393,13 @@ class ProxyServerCommand extends Command */ protected function configure() { - $this->setDescription('Start HTTP proxy server | 开启一个 HTTP 代理服务器'); + $this->setDescription('开启一个 HTTP 代理服务器'); $this->addOption('type', 't', InputOption::VALUE_REQUIRED, '类型,可选http、socks'); $this->addOption('host', 'H', InputOption::VALUE_REQUIRED, '监听地址,默认0.0.0.0'); $this->addOption('port', 'P', InputOption::VALUE_REQUIRED, '监听端口,默认8080'); $this->addOption('udp-port', 'U', InputOption::VALUE_REQUIRED, '监听端口,默认8080'); $this->addOption('username', 'u', InputOption::VALUE_REQUIRED, '认证用的用户名'); $this->addOption('password', 'p', InputOption::VALUE_REQUIRED, '认证用的密码'); - // ... } protected function execute(InputInterface $input, OutputInterface $output): int diff --git a/src/ZM/Command/ReplCommand.php b/src/ZM/Command/ReplCommand.php index 5ea101f2..1f8fe529 100644 --- a/src/ZM/Command/ReplCommand.php +++ b/src/ZM/Command/ReplCommand.php @@ -7,20 +7,15 @@ namespace ZM\Command; use Psy\Configuration; use Psy\Shell; use Psy\VersionUpdater\Checker; -use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Attribute\AsCommand; use ZM\Framework; +#[AsCommand(name: 'repl', description: '交互式控制台')] class ReplCommand extends Command { - protected static $defaultName = 'repl'; - - protected static $defaultDescription = '交互式控制台'; - - public function execute(InputInterface $input, OutputInterface $output): int + public function handle(): int { - $config = Configuration::fromInput($input); + $config = Configuration::fromInput($this->input); $config->setUpdateCheck(Checker::NEVER); $config->setStartupMessage('你可以使用 "help" 来查看帮助'); @@ -28,13 +23,13 @@ class ReplCommand extends Command $shell->addCommands([]); // TODO: add some great commands try { - $output->writeln(sprintf('Zhamao Repl on Zhamao Framework %s', Framework::VERSION)); + $this->info(sprintf('Zhamao Repl on Zhamao Framework %s', Framework::VERSION)); $shell->run(); } catch (\Throwable $e) { - $output->writeln(sprintf('%s', $e->getMessage())); - return Command::FAILURE; + $this->error($e->getMessage()); + return self::FAILURE; } - return Command::SUCCESS; + return self::SUCCESS; } } diff --git a/src/ZM/Command/Server/ServerReloadCommand.php b/src/ZM/Command/Server/ServerReloadCommand.php index 7829cd13..1479c015 100644 --- a/src/ZM/Command/Server/ServerReloadCommand.php +++ b/src/ZM/Command/Server/ServerReloadCommand.php @@ -5,18 +5,13 @@ declare(strict_types=1); namespace ZM\Command\Server; use Swoole\Process; +use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; +#[AsCommand(name: 'server:reload', description: '重载服务器')] class ServerReloadCommand extends ServerCommand { - protected static $defaultName = 'server:reload'; - - protected function configure() - { - $this->setDescription('重载框架'); - } - protected function execute(InputInterface $input, OutputInterface $output): int { parent::execute($input, $output); diff --git a/src/ZM/Command/Server/ServerStartCommand.php b/src/ZM/Command/Server/ServerStartCommand.php index 4c7e3f1a..c4374c6d 100644 --- a/src/ZM/Command/Server/ServerStartCommand.php +++ b/src/ZM/Command/Server/ServerStartCommand.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace ZM\Command\Server; use OneBot\Driver\Process\ProcessManager; +use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; @@ -13,20 +14,20 @@ use ZM\Exception\ZMKnownException; use ZM\Framework; use ZM\Process\ProcessStateManager; +#[AsCommand(name: 'server:start', description: '启动服务器', aliases: ['server'])] class ServerStartCommand extends ServerCommand { - protected static $defaultName = 'server'; - public static function exportOptionArray(): array { $cmd = new self(); $cmd->configure(); - return array_map(function ($x) { return $x->getDefault(); }, $cmd->getDefinition()->getOptions()); + return array_map(function ($x) { + return $x->getDefault(); + }, $cmd->getDefinition()->getOptions()); } protected function configure() { - $this->setAliases(['server:start']); $this->setDefinition([ new InputOption('config-dir', null, InputOption::VALUE_REQUIRED, '指定其他配置文件目录'), new InputOption('driver', null, InputOption::VALUE_REQUIRED, '指定驱动类型'), @@ -40,7 +41,6 @@ class ServerStartCommand extends ServerCommand new InputOption('private-mode', null, null, '启动时隐藏MOTD和敏感信息'), new InputOption('print-process-pid', null, null, '打印所有进程的PID'), ]); - $this->setDescription('Run zhamao-framework | 启动框架'); $this->setHelp('直接运行可以启动'); } diff --git a/src/ZM/Command/Server/ServerStatusCommand.php b/src/ZM/Command/Server/ServerStatusCommand.php index 4b0fe449..0b1ea089 100644 --- a/src/ZM/Command/Server/ServerStatusCommand.php +++ b/src/ZM/Command/Server/ServerStatusCommand.php @@ -4,18 +4,13 @@ declare(strict_types=1); namespace ZM\Command\Server; +use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; +#[AsCommand(name: 'server:status', description: '查看服务器状态')] class ServerStatusCommand extends ServerCommand { - protected static $defaultName = 'server:status'; - - protected function configure() - { - $this->setDescription('查看框架的运行状态'); - } - protected function execute(InputInterface $input, OutputInterface $output): int { parent::execute($input, $output); diff --git a/src/ZM/Command/Server/ServerStopCommand.php b/src/ZM/Command/Server/ServerStopCommand.php index 6159b7b0..6a6761a4 100644 --- a/src/ZM/Command/Server/ServerStopCommand.php +++ b/src/ZM/Command/Server/ServerStopCommand.php @@ -5,19 +5,18 @@ declare(strict_types=1); namespace ZM\Command\Server; use Swoole\Process; +use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use ZM\Process\ProcessStateManager; use ZM\Store\FileSystem; +#[AsCommand(name: 'server:stop', description: '停止服务器')] class ServerStopCommand extends ServerCommand { - protected static $defaultName = 'server:stop'; - protected function configure() { - $this->setDescription('停止运行的框架'); $this->setDefinition([ new InputOption('force', 'f', InputOption::VALUE_NONE, '强制停止'), ]); From 44c25f7fdd851b7228473477f113906b8cd48661 Mon Sep 17 00:00:00 2001 From: sunxyw Date: Sat, 17 Dec 2022 22:18:50 +0800 Subject: [PATCH 2/2] make commands lazily loaded --- src/ZM/Command/BuildCommand.php | 2 + src/ZM/Command/CheckConfigCommand.php | 33 +++++------- src/ZM/Command/Command.php | 15 +++++- src/ZM/Command/InitCommand.php | 2 + src/ZM/Command/NonPharLoadModeOnly.php | 20 ++++++++ src/ZM/Command/Server/ServerStartCommand.php | 2 +- src/ZM/Command/SourceLoadModeOnly.php | 20 ++++++++ src/ZM/ConsoleApplication.php | 54 +++++++++----------- 8 files changed, 98 insertions(+), 50 deletions(-) create mode 100644 src/ZM/Command/NonPharLoadModeOnly.php create mode 100644 src/ZM/Command/SourceLoadModeOnly.php diff --git a/src/ZM/Command/BuildCommand.php b/src/ZM/Command/BuildCommand.php index 4728171c..b3cb65f3 100644 --- a/src/ZM/Command/BuildCommand.php +++ b/src/ZM/Command/BuildCommand.php @@ -13,6 +13,8 @@ use Symfony\Component\Console\Output\OutputInterface; #[AsCommand(name: 'build', description: '将项目构建一个phar包')] class BuildCommand extends Command { + use NonPharLoadModeOnly; + /** * 配置 */ diff --git a/src/ZM/Command/CheckConfigCommand.php b/src/ZM/Command/CheckConfigCommand.php index 5534e60b..651e4ef0 100644 --- a/src/ZM/Command/CheckConfigCommand.php +++ b/src/ZM/Command/CheckConfigCommand.php @@ -5,57 +5,52 @@ declare(strict_types=1); namespace ZM\Command; use Symfony\Component\Console\Attribute\AsCommand; -use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Output\OutputInterface; #[AsCommand(name: 'check:config', description: '检查配置文件是否和框架当前版本有更新')] class CheckConfigCommand extends Command { + use SourceLoadModeOnly; + private $need_update = false; - protected function execute(InputInterface $input, OutputInterface $output): int + protected function handle(): int { - if (LOAD_MODE !== 1) { - $output->writeln('仅限在Composer依赖模式中使用此命令!'); - return 1; - } $current_cfg = getcwd() . '/config/'; - $remote_cfg = include_once FRAMEWORK_ROOT_DIR . '/config/global_old.php'; + $remote_cfg = include FRAMEWORK_ROOT_DIR . '/config/global_old.php'; if (file_exists($current_cfg . 'global.php')) { - $this->check($remote_cfg, 'global.php', $output); + $this->check($remote_cfg, 'global.php'); } if (file_exists($current_cfg . 'global.development.php')) { - $this->check($remote_cfg, 'global.development.php', $output); + $this->check($remote_cfg, 'global.development.php'); } if (file_exists($current_cfg . 'global.staging.php')) { - $this->check($remote_cfg, 'global.staging.php', $output); + $this->check($remote_cfg, 'global.staging.php'); } if (file_exists($current_cfg . 'global.production.php')) { - $this->check($remote_cfg, 'global.production.php', $output); + $this->check($remote_cfg, 'global.production.php'); } if ($this->need_update === true) { - $output->writeln('有配置文件需要更新,详情见文档 `https://framework.zhamao.xin/update/config`'); + $this->comment('有配置文件需要更新,详情见文档 `https://framework.zhamao.xin/update/config`'); } else { - $output->writeln('配置文件暂无更新!'); + $this->info('配置文件暂无更新!'); } - return 0; + return self::SUCCESS; } /** * @param mixed $remote * @param mixed $local */ - private function check($remote, $local, OutputInterface $out) + private function check($remote, $local) { - $local_file = include_once WORKING_DIR . '/config/' . $local; + $local_file = include WORKING_DIR . '/config/' . $local; if ($local_file === true) { $local_file = config('global'); } foreach ($remote as $k => $v) { if (!isset($local_file[$k])) { - $out->writeln('配置文件 ' . $local . " 需要更新!(当前配置文件缺少 `{$k}` 字段配置)"); + $this->comment("配置文件 {$local} 需要更新!(当前配置文件缺少 `{$k}` 字段配置)"); $this->need_update = true; } } diff --git a/src/ZM/Command/Command.php b/src/ZM/Command/Command.php index 9ded2f91..97893708 100644 --- a/src/ZM/Command/Command.php +++ b/src/ZM/Command/Command.php @@ -32,7 +32,20 @@ abstract class Command extends \Symfony\Component\Console\Command\Command { $this->input = $input; $this->output = $output; - return $this->handle(); + if ($this->shouldExecute()) { + return $this->handle(); + } + return self::SUCCESS; + } + + /** + * 是否应该执行 + * + * @return bool 返回 true 以继续执行,返回 false 以中断执行 + */ + protected function shouldExecute(): bool + { + return true; } /** diff --git a/src/ZM/Command/InitCommand.php b/src/ZM/Command/InitCommand.php index b45997da..48c028e2 100644 --- a/src/ZM/Command/InitCommand.php +++ b/src/ZM/Command/InitCommand.php @@ -13,6 +13,8 @@ use ZM\Exception\InitException; #[AsCommand(name: 'init', description: '初始化框架运行的基础文件')] class InitCommand extends Command { + use NonPharLoadModeOnly; + private string $base_path; private bool $force = false; diff --git a/src/ZM/Command/NonPharLoadModeOnly.php b/src/ZM/Command/NonPharLoadModeOnly.php new file mode 100644 index 00000000..7d85fdd0 --- /dev/null +++ b/src/ZM/Command/NonPharLoadModeOnly.php @@ -0,0 +1,20 @@ +error('此命令只能在非 Phar 模式下使用!'); + } + return false; + } +} diff --git a/src/ZM/Command/Server/ServerStartCommand.php b/src/ZM/Command/Server/ServerStartCommand.php index c4374c6d..b204aa31 100644 --- a/src/ZM/Command/Server/ServerStartCommand.php +++ b/src/ZM/Command/Server/ServerStartCommand.php @@ -14,7 +14,7 @@ use ZM\Exception\ZMKnownException; use ZM\Framework; use ZM\Process\ProcessStateManager; -#[AsCommand(name: 'server:start', description: '启动服务器', aliases: ['server'])] +#[AsCommand(name: 'server', description: '启动服务器', aliases: ['server:start'])] class ServerStartCommand extends ServerCommand { public static function exportOptionArray(): array diff --git a/src/ZM/Command/SourceLoadModeOnly.php b/src/ZM/Command/SourceLoadModeOnly.php new file mode 100644 index 00000000..e9d3b946 --- /dev/null +++ b/src/ZM/Command/SourceLoadModeOnly.php @@ -0,0 +1,20 @@ +error('此命令只能在源码模式下使用!'); + } + return false; + } +} diff --git a/src/ZM/ConsoleApplication.php b/src/ZM/ConsoleApplication.php index 7a0c5120..c181609a 100644 --- a/src/ZM/ConsoleApplication.php +++ b/src/ZM/ConsoleApplication.php @@ -4,22 +4,13 @@ declare(strict_types=1); namespace ZM; -use Phar; use Symfony\Component\Console\Application; +use Symfony\Component\Console\Attribute\AsCommand; +use Symfony\Component\Console\CommandLoader\FactoryCommandLoader; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -use ZM\Command\BotCraft\BotCraftCommand; -use ZM\Command\BuildCommand; -use ZM\Command\CheckConfigCommand; -use ZM\Command\Generate\SystemdGenerateCommand; -use ZM\Command\InitCommand; -use ZM\Command\ProxyServerCommand; -use ZM\Command\ReplCommand; -use ZM\Command\Server\ServerReloadCommand; -use ZM\Command\Server\ServerStartCommand; -use ZM\Command\Server\ServerStatusCommand; -use ZM\Command\Server\ServerStopCommand; use ZM\Exception\SingletonViolationException; +use ZM\Store\FileSystem; /** * 命令行启动的入口文件,用于初始化环境变量,并启动命令行应用 @@ -37,24 +28,29 @@ final class ConsoleApplication extends Application } // 初始化命令 - $this->add(new ServerStatusCommand()); // server运行状态 - $this->add(new ServerReloadCommand()); // server重载 - $this->add(new ServerStopCommand()); // server停止 - $this->add(new ServerStartCommand()); // 运行主服务的指令控制器 - $this->add(new SystemdGenerateCommand()); // 生成systemd文件 - $this->add(new BotCraftCommand()); // 用于从命令行创建插件 - $this->add(new ReplCommand()); // 交互式控制台 - $this->add(new ProxyServerCommand()); // HTTP 代理服务器 - if (LOAD_MODE === 1) { // 如果是 Composer 模式加载的,那么可以输入 check:config 命令,检查配置文件是否需要更新 - $this->add(new CheckConfigCommand()); - } - if (\Phar::running() === '') { // 不是 Phar 模式的话,可以执行打包解包初始化命令 - $this->add(new BuildCommand()); // 用于将整个应用打包为一个可执行的 phar - $this->add(new InitCommand()); // 用于在 Composer 模式启动下,初始化脚手架文件 - // $this->add(new PluginPackCommand()); // 用于打包一个子模块为 phar 并进行分发 - // $this->add(new PluginListCommand()); // 用于列出已配置的子模块列表(存在 zm.json 文件的目录) - // $this->add(new PluginUnpackCommand()); // 用于将打包好的 phar 模块解包到 src 目录中 + $command_classes = FileSystem::getClassesPsr4(zm_dir('src/ZM/Command'), 'ZM\\Command'); + $commands = []; + foreach ($command_classes as $command_class) { + try { + $command_class_ref = new \ReflectionClass($command_class); + } catch (\ReflectionException $e) { + logger()->error("命令 {$command_class} 无法加载!反射失败:" . $e->getMessage()); + continue; + } + if ($command_class_ref->isAbstract()) { + continue; + } + // 从 AsCommand 注解中获取命令名称 + $attr = $command_class_ref->getAttributes(AsCommand::class); + if (count($attr) > 0) { + $commands[$attr[0]->getArguments()['name']] = fn () => new $command_class(); + } else { + logger()->warning("命令 {$command_class} 没有使用 AsCommand 注解,无法被加载"); + } } + // 命令工厂,用于延迟加载命令 + $command_loader = new FactoryCommandLoader($commands); + $this->setCommandLoader($command_loader); self::$obj = $this; // 用于标记已经初始化完成 parent::__construct($name, ZM_VERSION);