mongdch / mon-console
the php console utils.
Requires
- php: >=7.2
Requires (Dev)
None
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
轻量级 PHP 命令行控制台工具库。提供指令注册与分发、参数解析、交互式输入、彩色输出,以及表格、列表、分割线、Loading 动画等终端渲染能力,无第三方依赖。
特性
- 三种指令形式:闭包、指令类、
Command接口实现 - 支持按目录扫描、按 PSR-4 规则自动注册指令
Input统一解析命令、位置参数、短标签、长标签,支持交互读取与密码输入Output支持 ANSI 彩色输出、块状消息、分割线、列表、表格、JSON、dump、输出缓冲- 内置 Spinner 加载动画
环境要求
- PHP >= 7.2
- 仅支持 CLI SAPI(依赖
STDIN/STDOUT/STDERR与$argv) - 扩展:
mbstring
安装
composer require mongdch/mon-console
或
git clone https://github.com/MonGDCH/mon-console
快速开始
新建入口文件 app(无扩展名,可直接执行):
#!/usr/bin/env php <?php declare(strict_types=1); require __DIR__ . '/vendor/autoload.php'; use mon\console\App; use mon\console\Command; use mon\console\Input; use mon\console\Output; class HelloCommand extends Command { protected static $defaultName = 'hello'; protected static $defaultAliasName = 'hi'; protected static $defaultDescription = 'Say hello'; protected static $defaultGroup = 'demo'; public function execute(Input $input, Output $output) { $name = $input->read('Your name? '); $output->write('Hello ' . $name); $output->table([['id' => '1', 'name' => $name]], 'Users', ['id', 'name']); } } $app = App::instance(); // 闭包指令 $app->add('demo', function (Input $input, Output $output) { $output->dataList(['php' => PHP_VERSION, 'os' => PHP_OS], 'Runtime'); }, ['alias' => 'd', 'desc' => 'Show runtime info']); // 指令类 $app->add(HelloCommand::getCommandName(), HelloCommand::class, [ 'desc' => HelloCommand::getCommandDesc(), 'alias' => HelloCommand::getCommandAliasName(), 'group' => HelloCommand::getCommandGroup(), ]); $app->run();
运行:
php app # 无指令时输出帮助信息
php app -h # 输出帮助信息
php app --help # 输出帮助信息
php app hello # 执行 hello 指令
php app hi # 通过别名执行 hello 指令
php app -hi # 通过别名执行 hello 指令
php app d # 通过别名执行 demo 指令
php app hello name:Mon # 传入命名参数
指令
定义指令
1. 继承 mon\console\Command
通过静态属性声明指令元信息,元信息由 App::load() 读取;手动 add() 时需自行传入(见下方注册方式)。
class HelloCommand extends \mon\console\Command { protected static $defaultName = 'hello'; // 指令名 protected static $defaultAliasName = 'hi'; // 别名 protected static $defaultDescription = 'Say hello'; // 描述 protected static $defaultGroup = 'demo'; // 分组,默认 available public function execute(\mon\console\Input $input, \mon\console\Output $output) { $output->write('Hello'); } }
2. 实现 mon\console\interfaces\Command
需要自行实现 getCommandName() 等静态方法,否则 load() 会跳过该类。
class HelloCommand implements \mon\console\interfaces\Command { public function execute(\mon\console\Input $input, \mon\console\Output $output) { $output->write('Hello'); } public static function getCommandName() { return 'hello'; } }
3. 闭包
$app->add('demo', function (Input $input, Output $output) { $output->write('Hello'); }, 'This is Demo Command!');
注册指令
App::add(string $command, mixed $handle, array|string $option = [])
$app->add('demo', $handler, [ 'alias' => 'd', // 别名 'desc' => '描述', // 帮助信息中的描述 'group' => 'available', // 帮助信息中的分组 ]);
$handle可以是闭包、指令类名(需实现 Command 接口)$option传字符串时等价于只设置desc,分组固定为available
App::load(string $path, string $namespace = '')
递归扫描目录,按 PSR-4 规则生成类名并注册:
$app->load(__DIR__ . '/command', 'app\command');
- 类名推导规则:
$namespace + 相对目录(分隔符转`)+ 文件名` - 只注册实现了
Command接口且存在getCommandName()方法的类(继承Command基类即自带该方法) - 类必须可被自动加载(composer autoload 或事先
require),否则会被静默跳过 $path不要以目录分隔符结尾,且必须是已存在的目录(不存在会抛UnexpectedValueException)
输入 Input
Input 为单例,可在指令中通过 $input 使用。
| 方法 | 说明 |
|---|---|
getCommand(): ?string |
当前执行的指令名 |
setCommand($command) |
设置指令名 |
getArgs(?string $key = null, $default = null) |
获取全部参数或指定参数 |
setArgs(array $val, bool $replace = false) |
设置参数 |
getSopt(?string $key = null, $default = null) |
获取短标签 |
setSopt(array $val, bool $replace = false) |
设置短标签 |
getlopt(?string $key = null, $default = null) |
获取长标签 |
setlopt(array $val, bool $replace = false) |
设置长标签 |
read(string $question = '', bool $nl = false): string |
读取标准输入,可先输出提示语 |
password(string $tips = 'Please Enter Password:'): string |
读取密码(见限制说明) |
getScript(): string |
执行的脚本路径 |
getFullScript(): string |
完整命令行 |
getPwd(): string |
当前工作目录 |
参数解析规则
解析只发生在指令之后的参数上,且指令必须位于第一个位置。
| 输入 | 解析结果 |
|---|---|
php app demo |
command = demo |
php app demo arg0 |
args[0] = 'arg0' |
php app demo name:value |
args['name'] = 'value' |
php app demo -a |
sopt['a'] = true |
php app demo -a:value |
sopt['a'] = 'value' |
php app demo -abc |
sopt['a'] = true、sopt['b'] = true、sopt['c'] = true |
php app demo --long |
lopt['long'] = true |
php app demo --long:value |
lopt['long'] = 'value' |
php app demo --long=value |
lopt['long'] = 'value' |
php app demo -- -x |
args[0] = '-x'(-- 之后全部作为参数) |
布尔值转换:on / yes / true → true,off / no / false → false,其余保持字符串。
输出 Output
Output 为单例,可在指令中通过 $output 使用。
| 方法 | 说明 |
|---|---|
write(string $messages, bool $nl = true, bool $quit = false): int |
标准输出,支持彩色标签 |
error(string $text = '', bool $nl = true): int |
输出到标准错误流 |
block(string $messages, string $type = 'INFO', bool $quit = false): int |
块状消息,如 [INFO] xxx |
splitLine(string $title = '', string $char = '-', int $width = 0): int |
分割线,$width=0 时按终端宽度 |
dataList(array $data, string $title = '', bool $sequence = false, array $opts = []): int |
列表 / 有序列表 |
table(array $data, string $title = 'Data Table', array $columns = []): int |
表格 |
json(array $data, bool $echo = true, int $flags = JSON_UNESCAPED_UNICODE) |
JSON 输出或返回字符串 |
dump(...$args): int |
格式化打印变量 |
startBuffer() / flush(bool $nl = false, bool $quit = false) / clearBuffer() / stopBuffer(...) |
输出缓冲控制 |
spinBegin() / spin() / spinEnd() |
Loading 动画,需循环调用 spin()(spinBegiin() 为兼容保留的旧方法名) |
$quit 参数可直接退出进程:true 表示退出码 0,整数表示指定退出码,false 表示不退出。
彩色标签
write()、dataList()、table() 等内部会渲染 <标签>内容</标签> 形式的颜色标签:
$output->write('<red>ERROR</red> <green>SUCCESS</green>');
支持的标签:black red green brown blue cyan white yellow magenta、light_red light_green light_blue light_cyan light_gray light_magenta light_yellow、bold underscore reverse、success info comment warning danger error。
也可直接使用 mon\console\libs\Style::color($text, $style) 对整段文本染色。
列表
$output->dataList(['php' => PHP_VERSION, 'os' => PHP_OS], 'Runtime'); $output->dataList(['first', 'second'], '', true); // 有序列表
可用 $opts 自定义:leftChar、sepChar、keyStyle、valStyle、keyMinWidth、keyMaxWidth、titleStyle、lastNewline。
表格
$data = [ ['id' => '1', 'name' => 'Mon'], ['id' => '2', 'name' => 'GDCH'], ]; $output->table($data, 'Users'); // 以首行键名作为表头 $output->table($data, 'Users', ['id', 'name']); // 自定义表头
直接使用 mon\console\libs\Table::create($data, $title, $opts) 可配置更多参数:
showBorder、leftIndent、titleStyle、headStyle、headBorderChar、bodyStyle、rowBorderChar、colBorderChar、columns(titlePos 为预留参数,当前未生效)。
单元格会统一转换为字符串:标量直接转换,布尔值显示为
(true)/(false),数组转为 JSON。列宽按显示宽度计算,中文/全角字符按 2 列对齐;空数据输出No data to display.。
Loading 动画
$output->spinBegin(); for ($i = 0; $i < 100; $i++) { $output->spin(); // 需要持续调用才能刷新帧 usleep(20000); } $output->spinEnd();
应用配置
| 方法 | 说明 |
|---|---|
App::instance(): App |
获取单例 |
App::setTitle(string $title): App |
设置帮助信息中的标题(支持 ASCII Art) |
App::setShowHelpCommand(bool $show): App |
是否在帮助列表中显示内置 help 指令 |
App::getCommand(): array |
获取手动注册的指令名列表 |
App::getVersion(): string |
获取版本号 |
注意事项
- 指令必须作为第一个参数传入;内置帮助支持
php app help、php app h、php app -h、php app --help。 - 别名同时支持带前缀与不带前缀两种调用:
php app d与php app -d等价,帮助信息中展示为alias: d。 - 长标签支持
--long:value与--long=value;-abc会拆分为a、b、c三个短标签;--之后的参数不再解析为标签。 - 指令不存在或执行抛异常时,
run()默认终止进程并返回非 0 退出码;传入$exit = false时不再退出,并返回对应状态码。 Input::read()在输入流结束(如管道重定向)时返回空字符串,不会阻塞或报错。- Windows 下密码输入优先使用 PowerShell
Read-Host -AsSecureString(输入不回显);未安装 PowerShell 时回退到 VBS 弹窗,此时输入内容明文可见。 splitLine()默认宽度依赖终端探测,无法探测时回退为 80;固定布局场景建议显式传入$width。- 颜色输出会自动检测终端与
NO_COLOR环境变量;重定向或管道输出时不再附加 ANSI 转义。
更新日志
1.1.8 修复参数解析、指令别名与退出码、错误输出通道、密码输入、表格中文对齐、颜色检测等问题
1.1.7 兼容 PHP 8.5
1.1.6 细节修复
1.1.5 增加输出染色
1.1.4 优化显示逻辑
1.1.3 新增 Spinner 加载动画
1.1.2 优化 help 输出
1.1.1 修正布尔值参数解析
1.1.0 调整代码结构,移除内置 version 指令
1.0.6 调整优化代码结构,移除内置的 version 指令
1.0.5 修正发布缺失的文件
1.0.4 优化注解
1.0.3 优化错误提示,调整命名空间
1.0.2 优化代码,优化 Windows 环境下 sh / bash 脚本不可用时的错误提示,PHP 版本要求降为 5.6 以上
1.0.1 完全使用 STDOUT 作为输出流,增加有序列表支持,修复 table 渲染问题
1.0.0 发布第一个版本