やりたいこと

フレームワークのタスクなどを実行する際に、きちんと進行しているかインジケータを表示させたい。ただし、処理数分だけ行数を重ねるのではなくて1行に上書きしていきたい。上手く説明できなくて歯がゆいんですけど、つまりこうではなくて、

doSomething ...  1/5
doSomething ...  2/5
doSomething ...  3/5
doSomething ...  4/5
doSomething ...  5/5 finished

こう。

doSomething ...  5/5 finished ← この行だけで更新されていく

わかりますかね…


解法:改行ではなく「キャリッジリターンを使う」

「キャリッジリターン」というのはカーソルを行末から行頭に戻すためのコードで改行コードを含まないので、そのコードまで行くとカーソルは同じ行の先頭に移動して入力を待ちます。で、次の行が入力されると前の行の上に上書きされます、と。

キャリッジ・リターン - Wikipedia


これを知る前は次のようなコードを書いていて、上のように処理数分行が表示されていました。

$STDOUT = fopen("php://stdout", "w");
fwrite($STDOUT, $message . PHP_EOL);
fclose($STDOUT);

文字列を標準出力に書き出して、改行。
これをこうすれば、1行が更新されていく処理が表現できます。

$STDOUT = fopen("php://stdout", "w");
fwrite($STDOUT, $message . "\r");
fclose($STDOUT);

1つの処理が完了したら次の処理…という風にしたい場合には、何かフラグを与えて、

$STDOUT = fopen("php://stdout", "w");
fwrite($STDOUT, $message . (($finished) ? PHP_EOL : "\r"));
fclose($STDOUT);

とすればいいのかな。
実行ログはこんな感じで表示されていきます。

doSomething ...  5/5 finished
doNextTask ...  23/23 finished
doLastTask ...  49/49 finished


どう考えてもCUIの基礎だなあ。

俺ってホントに何も知らないんだなと思いました。メモ。