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
相关产品推荐
相关产品推荐

