CLI 库

CodeIgniter 的 CLI 库让创建交互式命令行脚本变得简单,包括:

  • 向用户提示更多信息

  • 在终端中写入多色文本

  • 发出提示音(请友好使用!)

  • 在长时间任务期间显示进度条

  • 将长文本行换行以适应窗口宽度。

初始化类

由于 CLI 库的所有方法都是静态的,你无需创建其实例。相反,你只需确保控制器可以通过类上方的 use 语句找到它:

<?php

namespace App\Commands;

use CodeIgniter\CLI\BaseCommand;
use CodeIgniter\CLI\CLI;

class MyCommand extends BaseCommand
{
    // ...

    public function run(array $params)
    {
        // ...
    }
}

该类在文件首次加载时会自动初始化。

从用户获取输入

有时你需要向用户询问更多信息。他们可能没有提供可选的命令行参数,或者脚本可能遇到了一个已存在的文件,需要在覆盖前进行确认。这可以通过 prompt()promptByKey() 方法来处理。

备注

从 v4.3.0 版本开始,你可以使用 PhpStreamWrapper 为这些方法编写测试。 参见 测试 CLI 输入

prompt()

你可以通过将问题作为第一个参数传入来提供:

<?php

use CodeIgniter\CLI\CLI;

$color = CLI::prompt('What is your favorite color?');

你可以通过将默认值作为第二个参数传入,来提供一个默认答案,当用户直接按回车键时会使用该答案:

<?php

use CodeIgniter\CLI\CLI;

$color = CLI::prompt('What is your favorite color?', 'blue');

你可以通过将允许的答案数组作为第二个参数传入,来限制可接受的答案:

<?php

use CodeIgniter\CLI\CLI;

$overwrite = CLI::prompt('File exists. Overwrite?', ['y', 'n']);

最后,你可以将 验证 规则作为第三个参数传入答案输入:

<?php

use CodeIgniter\CLI\CLI;

$email = CLI::prompt('What is your email?', null, 'required|valid_email');

验证规则也可以用数组语法编写:

<?php

use CodeIgniter\CLI\CLI;

$email = CLI::prompt('What is your email?', null, ['required', 'valid_email']);

promptByKey()

对于提示,预定义的答案(选项)有时需要描述,或者过于复杂而无法通过其值来选择。 promptByKey() 允许用户通过键而不是值来选择选项:

<?php

use CodeIgniter\CLI\CLI;

$fruit = CLI::promptByKey('These are your choices:', ['The red apple', 'The plump orange', 'The ripe banana']);
/*
 * These are your choices:
 *   [0]  The red apple
 *   [1]  The plump orange
 *   [2]  The ripe banana
 *
 * [0, 1, 2]:
 */

命名键也是可能的:

<?php

use CodeIgniter\CLI\CLI;

$fruit = CLI::promptByKey(['These are your choices:', 'Which would you like?'], [
    'apple'  => 'The red apple',
    'orange' => 'The plump orange',
    'banana' => 'The ripe banana',
]);
/*
 * These are your choices:
 *   [apple]   The red apple
 *   [orange]  The plump orange
 *   [banana]  The ripe banana
 *
 * Which would you like? [apple, orange, banana]:
 */

最后,你可以将 验证 规则作为第三个参数传入答案输入,可接受的答案会自动限制为传入的选项。

promptByMultipleKeys()

Added in version 4.3.0.

此方法与 promptByKey() 相同,但支持多个值。

<?php

use CodeIgniter\CLI\CLI;

$hobbies = CLI::promptByMultipleKeys('Select your hobbies:', ['Playing game', 'Sleep', 'Badminton']);
/*
 * Select your hobbies:
 *   [0]  Playing game
 *   [1]  Sleep
 *   [2]  Badminton
 *
 * You can specify multiple values separated by commas.
 * [0, 1, 2]:
 *
 * if your answer is '0,2', the return is the key and the value of the options :
 * [
 *   [0] => "Playing game",
 *   [2] => "Badminton"
 * ]
 */

重要

方法 promptByMultipleKeys()promptByKey() 不同,不支持命名键或验证。

提供反馈

write()

提供了几种方法,让你可以向用户提供反馈。这可以是简单的状态更新,也可以是适应用户终端窗口宽度的复杂信息表。核心是 write() 方法,它将要输出的字符串作为第一个参数:

<?php

use CodeIgniter\CLI\CLI;

CLI::write('The rain in Spain falls mainly on the plains.');

你可以通过将颜色名称作为第二个参数传入来更改文本颜色:

<?php

use CodeIgniter\CLI\CLI;

CLI::write('File created.', 'green');

这可用于区分不同状态的消息,或通过使用不同颜色创建“标题”。你甚至可以通过将颜色名称作为第三个参数传入来设置背景色:

<?php

use CodeIgniter\CLI\CLI;

CLI::write('File overwritten.', 'light_red', 'dark_gray');

以下前景色可用:

  • black

  • dark_gray

  • blue

  • dark_blue

  • light_blue

  • green

  • light_green

  • cyan

  • light_cyan

  • red

  • light_red

  • purple

  • light_purple

  • light_yellow

  • yellow

  • light_gray

  • white

背景色可用的种类较少:

  • black

  • blue

  • green

  • cyan

  • red

  • yellow

  • light_gray

  • magenta

print()

print() 的功能与 write() 方法完全相同,只是它不会在前后强制换行。 相反,它会将内容打印到光标当前所在的位置。这允许你通过不同的调用在同一行上打印多个项目。当你想要显示一个状态,执行某个操作,然后在同一行上打印“Done”时,这尤其有用:

<?php

use CodeIgniter\CLI\CLI;

for ($i = 0; $i <= 10; $i++) {
    CLI::print($i);
}

color()

虽然 write() 命令会将单行写入终端,并以 EOL 字符结尾,但你可以使用 color() 方法创建一个字符串片段,其使用方式相同,只是它不会在打印后强制换行。这允许你在同一行上创建多个输出。或者,更常见的是,你可以在 write() 方法内部使用它来创建内部不同颜色的字符串:

<?php

use CodeIgniter\CLI\CLI;

CLI::write("fileA \t" . CLI::color('/path/to/file', 'white'), 'yellow');

此示例会将单行写入窗口,其中 fileA 为黄色,后跟一个制表符,然后是白色文本的 /path/to/file

error()

如果需要输出错误,你应该使用相应的 error() 方法。它会将浅红色文本写入 STDERR,而不是像 write()color() 那样写入 STDOUT。如果你有脚本在监视错误,这会很有用,这样它们就不必筛选所有信息,只需关注实际的错误消息。你使用它的方式与使用 write() 方法完全相同:

<?php

use CodeIgniter\CLI\CLI;

CLI::error('Cannot write to file: ' . $file);

wrap()

此命令将获取一个字符串,从当前行开始打印,并在新行上将其换行到设定的长度。 当你需要显示一个带有描述的选项列表,并希望这些描述在当前窗口内换行而不超出屏幕时,这可能会很有用:

<?php

use CodeIgniter\CLI\CLI;

CLI::color("task1\t", 'yellow');
CLI::wrap('Some long description goes here that might be longer than the current window.');

默认情况下,字符串将在终端宽度处换行。Windows 当前无法确定窗口大小,因此我们默认为 80 个字符。如果你想将宽度限制为更短的长度,以确保其能适应窗口,请将最大行长度作为第二个参数传入。这会在最近的单词边界处断开字符串,以避免单词被拆分。

<?php

use CodeIgniter\CLI\CLI;

// Wrap the text at max 20 characters wide
CLI::wrap($description, 20);

你可能会发现,你希望左侧有一列标题、文件或任务,而在右侧有一列对应的描述文本。默认情况下,换行会回到窗口的左边缘,这不允许内容在列中对齐。在这种情况下,你可以传入一定数量的空格来填充第一行之后的每一行,这样左侧就会有一个清晰的列边缘:

<?php

use CodeIgniter\CLI\CLI;

$titles = [
    'task1a',
    'task1abc',
];
$descriptions = [
    'Lorem Ipsum is simply dummy text of the printing and typesetting industry.',
    "Lorem Ipsum has been the industry's standard dummy text ever since the",
];

// Determine the maximum length of all titles
// to determine the width of the left column
$maxlen = max(array_map('strlen', $titles));

for ($i = 0; $i < count($titles); $i++) {
    CLI::write(
        // Display the title on the left of the row
        substr(
            $titles[$i] . str_repeat(' ', $maxlen + 3),
            0,
            $maxlen + 3,
        ) .
        // Wrap the descriptions in a right-hand column
        // with its left side 3 characters wider than
        // the longest item on the left.
        CLI::wrap($descriptions[$i], 40, $maxlen + 3),
    );
}

将创建类似以下内容:

task1a     Lorem Ipsum is simply dummy
           text of the printing and
           typesetting industry.
task1abc   Lorem Ipsum has been the
           industry's standard dummy
           text ever since the

newLine()

newLine() 方法会向用户显示一个空白行。它不接受任何参数:

<?php

use CodeIgniter\CLI\CLI;

CLI::newLine();

clearScreen()

你可以使用 clearScreen() 方法清空当前终端窗口。在大多数 Windows 版本中,这只会插入 40 个空白行,因为 Windows 不支持此功能。Windows 10 的 bash 集成可能会改变这一点:

<?php

use CodeIgniter\CLI\CLI;

CLI::clearScreen();

showProgress()

如果你有一个长时间运行的任务,并希望向用户实时更新进度,可以使用 showProgress() 方法,它会显示类似以下内容:

[####......] 40% Complete

该方块在原位置进行动画,效果非常不错。

使用时,将当前步骤作为第一个参数传入,将总步骤数作为第二个参数传入。完成百分比和显示长度将基于该数字确定。完成后,将第一个参数传为 false,进度条将被移除。

<?php

use CodeIgniter\CLI\CLI;

$totalSteps = count($tasks);
$currStep   = 1;

foreach ($tasks as $task) {
    CLI::showProgress($currStep++, $totalSteps);
    $task->run();
}

// Done, so erase it...
CLI::showProgress(false);

table()

<?php

use CodeIgniter\CLI\CLI;

$thead = ['ID', 'Title', 'Updated At', 'Active'];
$tbody = [
    [7, 'A great item title', '2017-11-15 10:35:02', 1],
    [8, 'Another great item title', '2017-11-16 13:46:54', 0],
];

CLI::table($tbody, $thead);
+----+--------------------------+---------------------+--------+
| ID | Title                    | Updated At          | Active |
+----+--------------------------+---------------------+--------+
| 7  | A great item title       | 2017-11-16 10:35:02 | 1      |
| 8  | Another great item title | 2017-11-16 13:46:54 | 0      |
+----+--------------------------+---------------------+--------+

wait()

等待一定数量的秒数,可选择性地显示等待消息并等待按键。

<?php

use CodeIgniter\CLI\CLI;

// wait for specified interval, with countdown displayed
CLI::wait($seconds, true);

// show continuation message and wait for input
CLI::wait(0, false);

// wait for specified interval
CLI::wait($seconds, false);