You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP CLI下如何实现字符水平移动单行刷新 避免输出多行结果

PHP CLI 实现同一行动态刷新字符移动效果的方案

核心实现原理

  • 不要用换行符\n/PHP_EOL结束输出,改用回车符\r,可以将光标移动到当前行的行首,后续输出会直接覆盖当前行的原有内容
  • 关闭PHP默认的输出缓冲,保证每次输出的内容立刻渲染到终端
  • 如果是多玩家需要显示多行轨道,可使用ANSI转义序列\033[H\033[J清空整个终端屏幕,再重新输出所有玩家的轨道,实现整页刷新

改动后的完整可运行代码

<?php
// 关闭输出缓冲,保证内容即时输出
ob_implicit_flush(true);
ob_end_flush();

$trackLength = 18;
$playerSymbol = "_";
$emptyTrack = array_fill(0, $trackLength, $playerSymbol);
$playerList = ["#", "X", 1, "$", "Y", 2, "!", "Z", 3, "@", "C", 4];
$ChosenPlayer = [];
$makePlayerTrack = [];

$randomMin = 1;
$randomMax = 2;
$oneStep = $randomMax - 1;

$runningInProgress = true;
$reachedFinish = [];

$playerCount = (int) readline("Please enter amount of participants: ");
if (!is_numeric($playerCount) || !(0 < $playerCount && $playerCount < count($playerList))){
    echo "Invalid input, valid range is 1~".(count($playerList)-1) . PHP_EOL;
    exit;
}

for ($i = 0; $i < $playerCount; $i++){
    $makePlayerTrack[$i] = $emptyTrack;
    $ChosenPlayer[] = $playerList[$i];
    $makePlayerTrack[$i][0] = $ChosenPlayer[$i];
}

while ($runningInProgress) {
    usleep(500000); // 调整到0.5秒步进,视觉效果更清晰,可自行修改
    
    // 单玩家直接用\r覆盖当前行,多玩家先清屏再输出所有轨道
    if ($playerCount === 1) {
        $trackStr = implode("", $makePlayerTrack[0]);
        echo $trackStr . "\r";
    } else {
        // ANSI转义序列:清空屏幕+光标回到左上角
        echo "\033[H\033[J";
        for ($i = 0; $i < $playerCount; $i++) {
            echo implode("", $makePlayerTrack[$i]) . PHP_EOL;
        }
    }

    $allFinished = true;
    for ($i = 0; $i < $playerCount; $i++){
        $position = array_search($ChosenPlayer[$i], $makePlayerTrack[$i]);
        if ($position === false) $position = $trackLength -1;
        
        if ($position < $trackLength - 1){
            $allFinished = false;
            $randomSpeed = rand($randomMin, $randomMax);
            $makePlayerTrack[$i][$position] = $playerSymbol;
            $newPosition = min($position + $randomSpeed, $trackLength - 1);
            $makePlayerTrack[$i][$newPosition] = $ChosenPlayer[$i];
        } else {
            if (!in_array($ChosenPlayer[$i], $reachedFinish)) {
                $reachedFinish[] = $ChosenPlayer[$i];
            }
        }
    }

    if ($allFinished) {
        // 最后输出一次结果,避免\r被后续内容覆盖
        if ($playerCount ===1) {
            echo implode("", $makePlayerTrack[0]) . PHP_EOL;
        }
        echo PHP_EOL . "Winner board: " . PHP_EOL;
        for ($i = 1; $i <= count($reachedFinish); $i++){
            echo "{$i}. " . $reachedFinish[$i - 1] . PHP_EOL;
        }
        $runningInProgress = false;
    }
}

关键改动说明

  • 开头加了ob_implicit_flush(true)和ob_end_flush(),关闭PHP输出缓冲,避免内容延迟渲染
  • 单玩家场景下,输出轨道后加\r而非换行符,实现同一行覆盖刷新
  • 多玩家场景下使用ANSI转义序列清空屏幕后重新输出所有轨道,实现整页动态刷新,不会产生多行历史内容
  • 修复了原代码中玩家到达终点的判断逻辑,避免提前结束比赛
  • 兼容单字符输入和多角色数组输入两种场景,单角色时设置playerCount=1即可

注意事项

  • 该效果仅能在CLI终端环境运行,无法在浏览器中实现
  • 旧版本Windows cmd可能需要开启ANSI支持才能正常清屏,Windows Terminal、PowerShell、macOS/Linux默认终端均无兼容性问题
  • 步长、刷新间隔可自行修改usleep参数和rand的取值范围,调整到符合需求的动画效果

内容的提问来源于stack exchange,提问作者Goaul

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 22:45:00