大阪市中央区 システムソフトウェア開発会社

営業時間:平日09:15〜18:15
MENU

PHPをC++の前処理に使う際に__FILE__定数をすり替える。

株式会社クローバーフィールドの経営理念
著者:高木信尚
公開日:2017/05/07
最終更新日:2017/05/07
カテゴリー:技術情報
タグ:

高木です。おはようございます。

先日、「PHPをC++の前処理に使う際に#line指令を埋め込む」という記事を書きました。
今回のその続きになります。

前回の記事で、「少なくとももうひとつ前処理を行う必要がある」と書きましたが、今回はそのことではなく、もう少しマイナーな機能です。
ただ、いくらマイナーな機能といっても、実用化のためには必要ですし、最初の段階で考えておくべきことなのです。

PHPでもCやC++と同様、__FILE__を使うことができます。
ただし、PHPの__FILE__はマクロではなく定数です。

マクロか定数かの違いはあっても、用途も使い方も同じです。
__FILE__の有用性については、あらためて書く必要はないでしょう。

前回、#line指令を埋め込むために、いったんソースコードを分解してから再結合し、文字列をPHPのevalで評価しました。
この方法を使うと、__FILE__定数を使っても当然うまくいきません。

#line指令でファイル名は指定しましたが、それはあくまでもC++コンパイラに教えるためのものです。
PHPはファイル名を知りませんから、何らかの方法で教えてあげなければなりません。

とはいえ、そのための気の利いた関数などは私が知る限りありませんから、#line指令を埋め込むついでに、__FILE__定数を実際のファイル名を表す文字列にすりかえてあげるしかありません。

前回のスクリプトを若干修正して、次のようにしてやることで__FILE__定数のすり替えができそうです。

<?php
$path = $argv[1];
$tokens = token_get_all(file_get_contents($path));

$source = "#line 1 \"" . __FILE__ . "\"\n";
foreach ($tokens as $token)
{
  if (!is_array($token))
  {
    $source .= $token;
  }
  else
  {
    switch ($token[0])
    {
      case T_CLOSE_TAG:
        $source .= "?>\n#line " . $token[2] . "\n";
        break;
      case T_FILE:
        $source .= "\"$path\"";
        break;
      default:
        $source .= $token[1];
        break;
    }
  }
}

eval("?>\n$source");

これで__FILE__定数をすり替えることはできました。
しかし、PHPの処理系が本当にファイル名を認識しているわけではないので、機能的な制限も出てきてしまいます。

具体的には、debug_backtrace関数なんかは期待した結果を返さないでしょうね。
Exception::getTraceメソッドなんかもそうです。
このあたりは割り切るしかなさそうです。

    上に戻る