nownab.log

nownabe's daily posts

ob_start についての補足

Posted on Apr 21, 2022

ob_start

はじめに

先日 ZUTOMAYO FACTORY「鷹は飢えても踊り忘れず」で表示されていたプログラムについて という記事を書きました。 この記事ではずっと真夜中でいいのに。のライブで現れた PHP のプログラムをずっと真夜中でいいのに。の世界観で解釈することを試みました。 その際に、ライブのタイトルにもなっている ob_start という関数にはどう解釈すればいいか悩まされました。 本記事は先日の記事の補足記事であり、先日の記事での解釈に PHP 素人が何を調べてどう至ったかという過程をメモしておきます。

本記事ではある程度の Web プログラミングの知識を前提とします。 もしエンジニアでない方がこの記事を読んでいたら、ob_start の特徴まとめ まで読み飛ばしてください。

PHP という言語

ob_start を理解するためにはまず PHP (PHP: Hypertext Preprocessor) の特徴を知っておく必要があります。 PHP は今では汎用言語として利用されていますが、元々はただの HTML 用のテンプレートツールであり、今でも HTML に埋め込むような構文を特徴としています。

例えば、現在の日付を HTML で表示したい場合、次のような PHP スクリプトで実現できます。

<!DOCTYPE html>
<html>
<head>
  <title>My Website</title>
</head>
<body>
  <h1>My Website</h1>
  <p>
<?php
  echo "今日の日付は";
  echo date("Y/m/d");
  echo "です。";
?>
  </p>
</body>
</html>

<?php ... ?> の部分が PHP のプログラムであり、これを実行すると次のような出力が得られます。

<!DOCTYPE html>
<html>
<head>
  <title>My Website</title>
</head>
<body>
  <h1>My Website</h1>
  <p>今日の日付は2022/04/21です。</p>
</body>

このように、<?php ... ?> で囲まれていない部分が PHP プログラムとして valid でありかつそのまま出力されるという仕様は、PHP の起源でもあり ob_start が必要となる重要な仕様でもあります。

ob_start とは

ob_start関数 は出力のバッファリングを有効にする関数です。 ob_start() で有効化したバッファに書き込んだ文字列を利用するには、ob_get_contents() で文字列として取得するか、 ob_end_flush() で出力します。 また、ob_start によるバッファはスタックができます。

ob_start() を使うと、上記のプログラムは次のように書けます。

<?php
  ob_start();
  echo "今日の日付は";
  echo date("Y/m/d");
  echo "です。";
  $date = ob_get_clean();
?>
<!DOCTYPE html>
<html>
<head>
  <title>My Website</title>
</head>
<body>
  <h1>My Website</h1>
  <p><?php echo $date; ?></p>
</body>
</html>

これぐらいの例だと使うメリットはないように思えますが、例えば Wordpress では多用されています。 WordPress では部分テンプレートの描画に使っていたり、複雑に HTML と PHP が混在するような描画処理を変数へ格納するのに使っていたりするようです。

WordPress では「ブラウザのエディタでユーザーが HTML + ちょっとしたスクリプティングで View を自由に書ける」ようになっています。 その実態は単純にユーザーが PHP スクリプトを書いているだけであり、それは PHP が HTML のテンプレートとして振舞い ob_start がそれを柔軟に扱うことで実現しています。

また、ob_start で PHP の出力を全部キャプチャーできるため、テストで使われることもあるようです。

ob_start の特徴まとめ

このように調べたところ、ob_start は以下のような説明が可能であることがわかりました。

  • 出力をバッファリングする
  • バッファリングした出力は文字列として取り出したり、出力せずに消去したりできる
  • バッファはスタッカブルである
  • HTML テンプレートの柔軟な構造化に用いられる
  • HTML と PHP が複雑に混在するような描画を処理するときに用いられる
  • テストで用いられる

ob_start の解釈

今回のプログラムを解釈する上で「HTML と PHP が複雑に混在するような描画を処理するときに用いられる」という特徴に注目しました。 これはつまり、ob_start が HTML と PHP という 2 つの世界を橋渡しする役割を担っています。

このことから、鷹踊プログラムに出てくる ob_start も何か 2 つの世界をつなげるという意味を持っているかもしれないと考えました。 鷹踊プログラムでは ob_start の直前でも2022年の $we と 2122年の $we2 をつなぐようなプログラムとなっています。

$we2 = Worker::getWorking(); // 私達は生きている。
assertFalse($we->place == $we2->place); // たとえ生きる居場所が違くたって
assertFalse($we->period == $we2->period); // たとえ生きる時代が違くたって
assertSame($we->enthusiasm, $we2->enthusiasm); // 私達の熱を決して奪うことは出来ない
/* 2122.04.17 */
ob_start();

もうひとつ重要なポイントとして、ob_start が「PHP の世界ではメインの処理であり存在目的でもある HTML の描画を今から初めますよ」という宣言であることにも注目しました。 成り立ちや使われ方、言語仕様からみても PHP は HTML を描画することが存在目的です。 もちろん PHP のプログラムは全体を見ると HTML を描画する以外にも多くの処理をこなしていますが、やはり主役であり最終目的は HTML の描画と言っていいでしょう。 そして、ob_start はその存在目的である HTML 描画の合図になっています。

このことから、鷹踊プログラムの ob_start も「自分の存在を開始する」というような意味がこめられているのではないかと考えました。

おわりに

熱が冷めないうちに、考えたことを忘れないうちに、補足を書いてみました。

ob_start() 以外の部分は比較的ストレートに解釈できる部分が多かったのですが ob_start に関してだけはこの記事に書いたようなプロセスで調べて考える必要がありました。 なかなかプログラマーじゃないと伝わらない ob_start のニュアンスや感覚はあるとは思いますが、何かの参考になれば幸いです。

先日の記事の感想と同じですが、プログラムをこのように読み解いていくのは非常に楽しい作業でした。 ずとまよには普段から素晴らしい音楽を提供してもらってるのに、こんな完成度が高く読み応えのあるプログラムまで提供してもらって感謝の念に堪えません。 プログラミングにこんな楽しさもあるんだというのは新しい発見でした。

それでは。