跳到主要内容
ansicode
PHP

在 PHP 中使用 ANSI 转义码

PHP CLI 模式(`php -r`、`php script.php`)的 STDOUT 按字节透传 —— `echo "\e[31mred\e[0m"` 自 PHP 5.4 起可用(该版本将 `\e` 引入双引号字符串;更早代码请用 `"\x1b"` 或 `chr(27)`)。Windows Conhost 自 Windows 10 1709 起原生解析 VT,但 PHP 官方建议显式调用 `sapi_windows_vt100_support(STDOUT, true)`(PHP 7.2+)切换模式,保证跨 host 与 CGI 回退一致。 超出零散 echo 的场景,**Symfony Console** 是 PHP CLI 框架的事实标准 —— Composer、Laravel `artisan`、Symfony `console`、Drupal `drush` 的底层。其 `OutputFormatter` 使用类 XML 标签(`<info>...</info>`、`<fg=red;bg=white;options=bold>...</>`)在底层编译成 ANSI,输出到非 TTY 时自动去色。**Termwind** 提供终端版 Tailwind CSS(`text-red-500`、`bg-blue-500`、`font-bold` 之类的 class 名),是 PHPStan、Pest、Laravel Zero 的底层。**laravel/prompts** 提供现代交互提示,可在 Laravel 之外独立使用。

推荐库

  • symfony/console

    PHP CLI 框架的事实标准 —— argv 解析、格式化输出、进度条、表格渲染、`QuestionHelper` 交互提示。输出用类 XML 标签:`<info>绿色</info>`、`<error>红底</error>`、`<fg=blue;bg=white;options=bold>...</>`。stdout 为非 TTY 时格式器自动去色。Composer、Laravel `artisan`、Symfony `console`、Drupal `drush` 都在用。

  • nunomaduro/termwind

    终端版 Tailwind CSS —— 用 class 名(`text-red-500`、`bg-blue-500`、`font-bold`、`mt-2`、`px-2`、`rounded`)与类 HTML 标签渲染(`render('<div class="text-red-500">oops</div>')`)。基于 Symfony Console 的 `OutputFormatter` 构建。PHPStan、Pest、Laravel Zero、Lambdish 的底层。

  • laravel/prompts

    现代交互提示 —— `text`、`password`、`confirm`、`select`、`multiselect`、`search`、`suggest`,外观抛光、支持键盘导航。Laravel 10+ 用其替代 Symfony Console 的 `QuestionHelper`,可在任意 PHP 项目独立安装使用。

  • league/climate

    PHP League 出品的 CLI 工具包 —— 彩色输出、表格、进度条、动画、填充、绘图辅助 —— 提供流式 API(`$climate->red()->bold()->out('oops')`)。无需完整命令路由脚手架时,比 Symfony Console 更轻量的替代方案。

常用写法

直接 echo —— \e 是 PHP 的 ESC 字面(5.4+)
<?php
echo "\e[1;31merror:\e[0m permission denied\n";

// PHP 5.3 fallback (no \e literal) — use \x1b or chr(27):
echo "\x1b[1;31merror:\x1b[0m permission denied\n";
Symfony Console —— 标签格式化输出
<?php
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Formatter\OutputFormatterStyle;

$out = new ConsoleOutput();

// <info>, <comment>, <question>, <error> ship by default. Define your own:
$out->getFormatter()->setStyle(
    'fire',
    new OutputFormatterStyle('red', null, ['bold'])
);

$out->writeln('<info>ok:</info> all 142 tests passed');
$out->writeln('<fire>error:</fire> permission denied');
$out->writeln('<fg=blue;bg=white;options=bold>highlighted</> back to normal');
// Auto-strips ANSI when stdout is piped (`php script.php | cat`).
能力门控 —— sapi_windows_vt100_support + isatty + NO_COLOR
<?php
// Stack the canonical signals in priority order:
//   --no-color flag → NO_COLOR env → FORCE_COLOR → !isatty → Win VT opt-in
function shouldUseColor(): bool {
    if (in_array('--no-color', $GLOBALS['argv'] ?? [], true)) return false;
    if (getenv('NO_COLOR') !== false) return false;
    if (getenv('FORCE_COLOR') !== false && getenv('FORCE_COLOR') !== '0') return true;

    // Windows: PHP 7.2+ exposes a switch for Conhost VT mode. Returns false
    // on legacy hosts (Windows 7/8) so the caller correctly falls back.
    if (DIRECTORY_SEPARATOR === '\\') {
        return function_exists('sapi_windows_vt100_support')
            && sapi_windows_vt100_support(STDOUT, true);
    }

    // POSIX: STDOUT must be a real TTY.
    return function_exists('posix_isatty') && posix_isatty(STDOUT);
}

$useColor = shouldUseColor();
$paint = fn(string $sgr, string $text): string =>
    $useColor ? "\e[{$sgr}m{$text}\e[0m" : $text;

echo $paint('1;31', 'error:'), ' permission denied', "\n";
Symfony Console ProgressBar 进度条
<?php
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Output\ConsoleOutput;

$out = new ConsoleOutput();
$progress = new ProgressBar($out, 100);
$progress->setFormat(' %current%/%max% [%bar%] %percent:3s%%  %elapsed:6s%');
$progress->setBarCharacter('<fg=green>=</>');
$progress->setProgressCharacter('<fg=green>></>');
$progress->setEmptyBarCharacter('<fg=gray>-</>');
$progress->start();

for ($i = 0; $i < 100; $i++) {
    usleep(20_000);
    $progress->advance();
}
$progress->finish();
$out->writeln('');

相关序列

其他语言