jbzoo/cli
该框架帮助创建CLI工具,并为symfony/console, symfony/process提供新工具。
Requires
- php: ^8.1
- bluepsyduck/symfony-process-manager: >=1.3.3
- jbzoo/event: ^7.0
- jbzoo/utils: ^7.1
- monolog/monolog: ^3.4
- symfony/console: >=6.4
- symfony/lock: >=6.4
- symfony/process: >=6.4
Requires (Dev)
- jbzoo/toolbox-dev: ^7.1
README
为什么?
该库极大地扩展了CLI应用程序的功能,并帮助在PHP中更快、更轻松地创建新的控制台工具。以下是为什么这个库是必需的总结:
-
增强功能
- 该库为Symfony/Console提供动力,简化了控制台工具的开发。
-
进度条改进
- 开发者可以获得一个针对循环操作优化的进度条,并增加了调试信息。这使得跟踪任务进度和诊断问题变得轻而易举。请参阅DemoProgressBar.php和实时演示。
- 在CliCommand中将
$this->_($messages, $level, $context)
作为部分替换Symfony/Console中的$output->writeln()
。 - 将
cli($messages, $level, $context)
作为不同类的别名。 - 在CliCommand中将
$this->progressBar(iterable|int $listOrMax, \Closure $callback, string $title = '')
作为部分替换Symfony/Console ProgressBar。
-
严格的类型转换
- 一个显著的特点是允许严格转换选项值,确保数据完整性并减少运行时错误。请参阅DemoOptionsStrictTypes.php。
- 对值列表进行内置验证。请参阅清理输入变量。
-
样式和输出定制
- 借助内置样式和颜色方案,开发者可以使他们的控制台输出更具可读性和视觉吸引力。请参阅DemoStyles.php。
-
消息别名
- 该库引入了强大的消息输出别名,允许简洁、一致的命令调用。这在保持代码清洁方面特别有帮助。
-
高级选项
- 诸如性能分析、时间戳、错误静默和专用输出模式(如cron和logstash模式)等特性使开发者能够根据其特定需求细化其控制台输出和诊断。
- 使用
--profile
选项显示时间和内存使用信息。 - 使用
--timestamp
选项在每个消息的开头显示时间戳。 - 禁用任何错误。所以退出码始终为
0
(如果可能)使用--mute-errors
。 - 在带有
--non-zero-on-error
选项的情况下,任何非零退出码的StdErr消息。 - 对于任何错误消息,应用程序将使用StdOut而不是StdErr
--stdout-only
选项(风险自负!)。 - 使用
--no-progress
选项禁用日志的进度条动画。
-
灵活的输出模式
- 库提供不同的输出格式,以适应各种用例。无论是关注用户友好的文本、日志还是与ELK Stack等工具的集成,都有为您量身定制的输出模式。
--output-mode=text
。默认情况下,文本输出格式。用户友好且易于阅读。--output-mode=cron
。它主要关注日志输出。它是--timestamp --profile --stdout-only --no-progress -vv --no-ansi
的组合。--output-mode=logstash
。它主要关注ELK Stack的Logstash格式。这也意味着--stdout-only --no-progress -vv
。
-
附加功能
在线演示
输出常规消息
进度条演示
快速入门 - 构建你的第一个CLI应用程序
安装
composer require jbzoo/cli
最简单的CLI应用程序具有以下文件结构。有关更多详细信息,请参阅演示应用程序。
文件结构
/path/to/app/
my-app # Binrary file (See below)
composer.json # Composer file
/Commands/ # Commands directory
Simple.php # One of the commands (See below)
/vendor/
autoload.php # Composer autoload
Composer文件
查看详细信息
{ "name" : "vendor/my-app", "type" : "project", "description" : "Example of CLI App based on JBZoo/CLI", "license" : "MIT", "keywords" : ["cli", "application", "example"], "require" : { "php" : ">=8.1", "jbzoo/cli" : "^7.1.0" }, "autoload" : { "psr-4" : {"DemoApp\\" : ""} }, "bin" : ["my-app"] }
二进制文件
二进制文件:demo/my-app
查看详细信息
#!/usr/bin/env php <?php declare(strict_types=1); namespace DemoApp; use JBZoo\Cli\CliApplication; // Init composer autoloader require_once __DIR__ . '/vendor/autoload.php'; // Optional. Set your application name and version. $application = new CliApplication('My Console Application', 'v1.0.0'); // Optional. Looks at the online generator of ASCII logos // https://patorjk.com/software/taag/#p=testall&f=Epic&t=My%20Console%20App $application->setLogo( <<<'EOF' __ __ _____ _ | \/ | / ____| | | /\ | \ / |_ _ | | ___ _ __ ___ ___ | | ___ / \ _ __ _ __ | |\/| | | | | | | / _ \| '_ \/ __|/ _ \| |/ _ \ / /\ \ | '_ \| '_ \ | | | | |_| | | |___| (_) | | | \__ \ (_) | | __/ / ____ \| |_) | |_) | |_| |_|\__, | \_____\___/|_| |_|___/\___/|_|\___| /_/ \_\ .__/| .__/ __/ | | | | | |___/ |_| |_| EOF, ); // Scan directory to find commands. // * It doesn't work recursively! // * They must be inherited from the class \JBZoo\Cli\CliCommand $application->registerCommandsByPath(__DIR__ . '/Commands', __NAMESPACE__); // Optional. Action name by default (if there is no arguments) $application->setDefaultCommand('list'); // Run application $application->run();
简单的CLI操作
最简单的CLI操作:./demo/Commands/DemoSimple.php
查看详细信息
<?php declare(strict_types=1); namespace DemoApp\Commands; use JBZoo\Cli\CliCommand; use JBZoo\Cli\Codes; class Simple extends CliCommand { protected function configure(): void { // Action name. It will be used in command line. // Example: `./my-app simple` $this->setName('simple'); // Defined inhereted CLI options. See ./src/CliCommand.php for details. parent::configure(); } protected function executeAction(): int { // Your code here $this->_('Hello world!'); // Exit code. 0 - success, 1 - error. return self::SUCCESS; } }
内置功能
清理输入变量
作为实时演示,请查看演示应用程序 - ./demo/Commands/DemoOptionsStrictTypes.php。
尝试启动./my-app options-strict-types
。
// If the option has `InputOption::VALUE_NONE` it returns true/false. // --option-name $value = $this->getOpt('option-name'); // `$value === true` // --option-name=" 123.6 " $value = $this->getOpt('option-name'); // Returns the value AS-IS. `$value === " 123.6 "` // --option-name=" 123.6 " $value = $this->getOptBool('option-name'); // Converts an input variable to boolean. `$value === true` // --option-name=" 123.6 " $value = $this->getOptInt('option-name'); // Converts an input variable to integer. `$value === 123` $value = $this->getOptInt('option-name', 42, [1, 2, 42]); // Strict comparing with allowed values // --option-name=" 123.6 " $value = $this->getOptFloat('option-name'); // Converts an input variable to float. `$value === 123.6` $value = $this->getOptFloat('option-name', 1.0, [1.0, 2.0, 3.0]); // Strict comparing with allowed values // --option-name=" 123.6 " $value = $this->getOptString('option-name'); // Converts an input variable to trimmed string. `$value === "123.6"` $value = $this->getOptString('option-name', 'default', ['default', 'mini', 'full']); // Strict comparing with allowed values // --option-name=123.6 $value = $this->getOptArray('option-name'); // Converts an input variable to trimmed string. `$value === ["123.6"]` // --option-name="15 July 2021 13:48:00" $value = $this->getOptDatetime('option-name'); // Converts an input variable to \DateTimeImmutable object. // Use standard input as input variable. // Example. `echo " Qwerty 123 " | php ./my-app agruments` $value = self::getStdIn(); // Reads StdIn as string value. `$value === " Qwerty 123 \n"`
以不同颜色和样式渲染文本
有预定义的颜色列表
<black> Text in Black color </black> <red> Text in Red Color </red> <green> Text in Green Color </green> <yellow> Text in Yellow Color </yellow> <blue> Text in Blue Color </blue> <magenta>Text in Magenta Color</magenta> <cyan> Text in Cyan Color </cyan> <white> Text in White Color </white> <!-- Usually default color is white. It depends on terminal settings. --> <!-- You should use it only to overwrite nested tags. --> <default>Text in Default Color</default>
有预定义的样式列表
<bl>Blinked Text</bl> <b>Bold Text</b> <u>Underlined Text</u> <r>Reverse Color/Backgroud</r> <bg>Change Background Only</bg>
您还可以组合颜色和样式。
<magenta-bl>Blinked text in magenta color</magenta-bl> <magenta-b>Bold text in magenta color</magenta-b> <magenta-u>Underlined text in magenta color</magenta-u> <magenta-r>Reverse text in magenta color</magenta-r> <magenta-bg>Reverse only background of text in magenta color</magenta-bg>
还有Symfony Console标准样式的预定义快捷键
<i> alias for <info> <c> alias for <commnet> <q> alias for <question> <e> alias for <error>
详细级别
控制台命令有不同的详细级别,这些详细级别决定了其输出中显示的消息。
作为实时演示,请查看演示应用程序 - ./demo/Commands/ExamplesOutput.php。您可以看到演示视频。
使用详细级别的示例
// There two strictly(!) recommended output ways: /** * Prints a message to the output in the command class which inherits from the class \JBZoo\Cli\CliCommand * * @param string|string[] $messages Output message(s). Can be an array of strings or a string. Array of strings will be imploded with new line. * @param string $verboseLevel is one of value form the class \JBZoo\Cli\OutLvl::* * @param string $context is array of extra info. Will be serialized to JSON and displayed in the end of the message. */ $this->_($messages, $verboseLevel, $context); /** * This is global alias function of `$this->_(...)`. * It's nice to have it if you want to display a text from not CliCommand class. */ JBZoo\Cli\cli($messages, $verboseLevel, $context);
# Do not output any message ./my-app output -q ./my-app output --quiet # Normal behavior, no option required. Only the most useful messages. ./my-app output # Increase verbosity of messages ./my-app output -v # Display also the informative non essential messages ./my-app output -vv # Display all messages (useful to debug errors) ./my-app output -vvv
内存和时间分析
作为实时演示,请查看演示应用程序 - ./demo/Commands/DemoProfile.php。
尝试启动./my-app profile --profile
。
进度条
作为实时演示,请查看演示应用程序 - ./demo/Commands/DemoProgressBar.php和实时演示。
您可以将此视为要分析的长循环的替代品。
请注意,在--verbose
模式下,计算所有额外的调试信息会在内存和运行时产生额外的开销。
简单示例
$this->progressBar(5, function (): void { // Some code in loop });
高级用法
$this->progressBar($arrayOfSomething, function ($value, $key, $step) { // Some code in loop if ($step === 3) { throw new ExceptionBreak("Something went wrong with \$value={$value}. Stop the loop!"); } return "<c>Callback Args</c> \$value=<i>{$value}</i>, \$key=<i>{$key}</i>, \$step=<i>{$step}</i>"; }, 'Custom messages based on callback arguments', $throwBatchException);
辅助函数
作为实时演示,请查看演示应用程序 - ./demo/Commands/DemoHelpers.php。
尝试启动./my-app helpers
。
JBZoo/Cli使用Symfony Question Helper作为别名的基。
常见问题
提出任何自定义问题,等待用户的输入。您可以设置默认值。
$yourName = $this->ask("What's your name?", 'Default Noname'); $this->_("Your name is \"{$yourName}\"");
询问用户的密码
提出一个问题并隐藏响应。这对于密码特别方便。您可以设置随机值作为默认值。
$yourSecret = $this->askPassword("New password?", true); $this->_("Your secret is \"{$yourSecret}\"");
让用户选择选项
如果您有一个用户可以选择的预定义答案集,可以使用 askOption
方法,确保用户只能从预定义列表中输入有效的字符串。可以选择设置默认选项(索引或字符串)。
$selectedColor = $this->askOption("What's your favorite color?", ['Red', 'Blue', 'Yellow'], 'Blue'); $this->_("Selected color is {$selectedColor}");
表示是/否问题
假设您想在执行实际操作之前确认操作。请将以下内容添加到您的命令中。
$isConfirmed = $this->confirmation('Are you ready to execute the script?'); $this->_("Is confirmed: " . ($isConfirmed ? 'Yes' : 'No'));
渲染键=>值列表
如果您需要显示对齐的列表,请使用以下代码。
use JBZoo\Cli\CliRender; $this->_(CliRender::list([ "It's like a title", 'Option Name' => 'Option Value', 'Key' => 'Value', 'Another Key #2' => 'Qwerty', ], '*')); // It's bullet character
* It's like a title
* Option Name : Option Value
* Key : Value
* Another Key #2: Qwerty
易于记录
简单日志
./my-app output --timestamp >> /path/to/crontab/logs/$(date +%Y-%m-%d).log 2>&1
计划任务
只需添加 --output-mode=cron
标志,并将输出保存到文件。特别是,这对于保存 Crontab 的日志非常方便。
./my-app output --output-mode=cron >> /path/to/crontab/logs/$(date +%Y-%m-%d).log 2>&1
Elasticsearch / Logstash (ELK)
只需添加 --output-mode=logstash
标志,并将输出保存到文件。特别是,这对于保存 ELK Stack 的日志非常方便。
./my-app output --output-mode=logstash >> /path/to/logstash/logs/$(date +%Y-%m-%d).log 2>&1
多进程
存在一种多进程模式(请勿将其与多线程混淆),用于加快与单调数据集的工作速度。基本上,JBZoo\Cli
将为每个数据集启动一个独立的子进程(不是线程!)并等待它们全部执行(就像 Promise 一样)。这就是您获得加速的方式,这取决于您服务器的性能和数据处理的算法。
您将看到一个简单的进度条,但您无法像在正常模式下那样进行性能分析和日志记录。
示例请在此处查找
注意
- 请注意
executeOneProcess()
和getListOfChildIds()
方法,这些方法用于管理子进程。它们是从CliCommandMultiProc
类继承的。 - 最佳子进程数量是
CPU 核心数 - 1
。您可以通过设置 CLI 选项来覆盖此值。有关详细信息,请参阅此处 ./src/CliCommandMultiProc.php。 - 请务必注意并发。调试起来并不容易。请尝试使用
-vvv
选项查看所有错误和警告。
技巧与窍门
- 使用类
\JBZoo\Cli\Codes
获取所有可用的退出代码。 - 您可以为任何消息添加额外的上下文。它将被序列化为 JSON 并显示在消息的末尾。只需使用
CliHelper::getInstance()->appendExtraContext(['section' => ['var' => 'value']]);
- 您可以将常量
\JBZOO_CLI_TIMESTAMP_REAL=true
定义为添加timestamp_real
作为额外上下文。有时这对于 Logstash 很有用,如果默认值@timestamp
对您不起作用。
贡献
# Fork the repo and build project make update # Make your local changes # Run all tests and check code style make test-all # Create your pull request and check all tests on GithubActions page
有用的项目和链接
- Symfony/Console 文档
- kevinlebrun/colors.php - 终端的新颜色
- php-school/cli-menu - 带嵌套项的交互式菜单
- nunomaduro/collision - 美观的错误报告
- splitbrain/php-cli - 轻量级且无依赖项的 CLI 框架
- thephpleague/climate - 允许您轻松输出彩色文本和特殊格式
- 具有特殊含义的退出代码
- 如何在 bash 中重定向标准错误(stderr)
许可证
MIT
另请参阅
- CI-Report-Converter - 转换不同的错误报告,以与流行的 CI 系统深度兼容。
- Composer-Diff - 查看
composer update
后已更改的包。 - Composer-Graph - 基于 mermaid-js 的 composer.json 依赖关系图可视化。
- Mermaid-PHP - 使用 mermaid 脚本语言生成图表和流程图。
- Utils - 收集有用的 PHP 函数、迷你类和日常片段。
- Image - 包提供了一种面向对象的简单方式来处理图像。
- 数据 - ArrayObject的扩展实现。使用文件作为配置/数组。
- Retry - 一个小巧的PHP库,提供重试/退避功能,支持多种退避策略和抖动支持。
- SimpleTypes - 转换任何值和度量 - 货币、重量、汇率、长度等。