registerCommandLoader(); // 执行父级初始化 parent::__construct($name, ZM_VERSION); $this->registerGlobalOptions(); // 设置命令事件分发器 $dispatcher = new EventDispatcher(); $this->setDispatcher($dispatcher); // 注册命令执行前监听器 $dispatcher->addListener(ConsoleEvents::COMMAND, function (ConsoleCommandEvent $event) { $input = $event->getInput(); // 初始化内核 /** @var Framework $kernel */ $kernel = Framework::getInstance(); $kernel->setConfigDir($input->getOption('config-dir')); $kernel->setEnvironment($input->getOption('env')); $kernel->setDebugMode($input->getOption('debug')); $kernel->setLogLevel($input->getOption('log-level')); $kernel->bootstrap(); }); // 注册命令执行错误监听器 $dispatcher->addListener(ConsoleEvents::ERROR, function (ConsoleErrorEvent $event) { $e = $event->getError(); // 输出错误信息 echo zm_internal_errcode('E00005') . "{$e->getMessage()} at {$e->getFile()}({$e->getLine()})" . PHP_EOL; exit(1); }); // 设置单例,阻止后续实例化 self::$obj = $this; } /** * 注册全局选项,应用到所有命令 */ public function registerGlobalOptions(): void { $this->getDefinition()->addOptions([ new InputOption('debug', 'd', InputOption::VALUE_NONE, '启用调试模式'), new InputOption('env', 'e', InputOption::VALUE_REQUIRED, '指定运行环境', 'development'), new InputOption('config-dir', 'c', InputOption::VALUE_REQUIRED, '指定配置文件目录', SOURCE_ROOT_DIR . '/config'), new InputOption('log-level', 'l', InputOption::VALUE_REQUIRED, '指定日志等级', 'info'), ]); } /** * 注册命令加载器 */ private function registerCommandLoader(): void { // 初始化命令 $command_classes = []; // 先加载框架内置命令 $command_classes = array_merge( $command_classes, FileSystem::getClassesPsr4(FRAMEWORK_ROOT_DIR . '/src/ZM/Command', 'ZM\\Command') ); // 再加载用户自定义命令(如存在) if (is_dir(SOURCE_ROOT_DIR . '/src/Command')) { $command_classes = array_merge( $command_classes, FileSystem::getClassesPsr4(SOURCE_ROOT_DIR . '/src/Command', 'Command') ); } // TODO: 加载插件命令,可以考虑自定义 CommandLoader $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); } }