yii2 console 控制器必须继承 yiiconsolecontroller,置于 @console/controllers/ 下,类名匹配文件名,action 方法需 public 且以 action 开头;不可用 web 控制器基类,否则报 unknown command 或 class not found。

怎么在 Yii2 里注册一个可执行的 console 控制器
必须继承 yiiconsoleController,不能用 web 控制器基类。Yii2 的 console 应用和 web 应用是两套独立的启动流程,控制器类路径、自动加载、命令解析机制都不同。
常见错误现象:Unknown command 或 Class not found,本质是控制器没被正确发现或继承关系不对。
- 控制器文件放在
@console/controllers/目录下(默认约定),类名需匹配文件名,如SendEmailController.php→consolecontrollersSendEmailController - 类必须 extends
yiiconsoleController,不是yiiwebController - 控制器内至少定义一个以
action开头的 public 方法,比如actionSend(),它才会被识别为可执行命令 - 确保
console/config/main.php中已配置'controllerMap'或依赖默认自动扫描(默认开启,但要求命名规范)
为什么 runAction() 在 console 控制器里不生效
runAction() 是 web 控制器常用方式,但在 console 环境下直接调用它不会触发参数绑定、选项解析、退出码处理等关键逻辑——console 命令执行链路是 Application::run() → Controller::runAction()(带上下文封装),手动调用会绕过整个命令生命周期。
使用场景:写单元测试、调试单个 action、或从其他命令中“调用”另一个命令逻辑时容易误用。
- 真要复用逻辑,把核心代码抽成独立服务类,而非在 controller 内调用
$this->runAction('send') - 若必须模拟命令执行(如测试),用
Yii::$app->runAction('send-email/send', ['--dry-run' => true]),这是安全入口 - 注意
runAction()返回的是 action 执行结果(比如 int/String),不是 exit code;console 命令预期返回整数退出码,0表示成功
怎么传参和读取 console 命令的选项(–flag)和参数(arg)
Yii2 console 使用 yiiconsoleRequest 解析命令行输入,默认支持位置参数 + 长短选项(--env=prod 或 -e prod),但需要显式声明才能被自动注入或验证。
参数差异直接影响健壮性:未声明的 --force 不会报错,但 $this->options 里拿不到;声明了却没在 action 签名中接收,会导致运行时报错 Unknown option: --force。
- 在控制器类中定义
public $options = ['env', 'force'];,声明哪些选项允许出现 - 在 action 方法签名里接收:
public function actionSend($to, $template, $env = 'dev'),位置参数按顺序绑定,选项则按名称映射 - 用
$this->isColorEnabled()或$this->ansiFormat()控制输出颜色,避免日志管道化时出乱码 - 别依赖
$argv手动解析——破坏 Yii 的统一参数处理,且无法兼容yiihelpersConsole::confirm()等交互式方法
为什么 console 命令执行后没输出、卡住、或报 Class ‘Yii’ not defined
最常踩的坑是环境配置错位:console 应用没加载对应组件,或用了 web 专属的 helper、view、session 等。
性能影响明显:比如在 console 里调用 Yii::$app->user->identity,会触发 session 启动和 cookie 处理,不仅失败还拖慢执行。
- 检查
console/config/main.php是否漏配数据库组件('db')、缓存('cache')等依赖项,console 默认不加载 web 配置 - 禁止在 console 控制器中使用
Yii::$app->request(它是yiiwebRequest),console 用的是yiiconsoleRequest - 避免在 init() 或构造函数里做 heavy 初始化(如加载大文件、连接外部服务),命令可能被频繁调用,应懒加载
- 如果用 composer 自动加载,确认
autoload-dev没把测试类误加进生产 autoload,导致 console 启动时类加载失败
console 控制器看着简单,但和 web 路由、生命周期、依赖注入完全隔离,任何跨环境假设都会立刻暴露。最易忽略的是:命令退出前没显式 return 整数,或者抛出未捕获异常——这会让 crontab 认为任务失败,但日志里只有一行 PHP Fatal Error。