質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.35%

  • PHP

    25496questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

PHPでPHPコードを解析したい

解決済

回答 4

投稿

  • 評価
  • クリップ 3
  • VIEW 2,417

sounisi5011

score 711

KwartzのPHP版がダウンロード出来ないため、またセレクタが貧弱なため、自前で作ってみようと考えています。

この際、独自形式のテキストファイルに記述された{}で囲まれた範囲のPHPコードを正確に抽出し、かつ、特定の関数や定数、変数を、文字列に置き換える処理が必要になります。

{}で囲まれた範囲のPHPコードを抽出するだけでも厄介です。
PHPコード内では制御構造・コールバックに使用する{}やそのネスト、文字列('',"")の他、ヒアドキュメントNowdoc実行演算子などでも{}が出現します。
これら全てを考慮し、PHPコードの終了位置にある}を抽出するだけでも面倒です。

またそれ以外に、特定の名前の関数を実行している箇所の式などを、PHPコードを文字列として扱いつつ別のコードに置き換えなくてはなりません。

例えば、関数_elemの実行箇所を置き換える場合、以下のようになります:
$i = 0;
foreach ($list as $user) {
  $color = ++$i % 2 == 0 ? '#FFCCCC' : '#CCCCFF';
  _elem();
}

$i = 0;
foreach ($list as $user) {
  $color = ++$i % 2 == 0 ? '#FFCCCC' : '#CCCCFF';
  ?>
      <tr bgcolor="<?php echo $color; ?>">
        <td><?php echo htmlspecialchars($user['name']); ?></td>
        <td><?php echo $user['mail']; ?></td>
      </tr>
<?php
}
関数_elemの実行箇所を、別のPHPコードで置き換えています。
  $i = 0;
  foreach ($list as $user) {
    $color = ++$i % 2 == 0 ? '#FFCCCC' : '#CCCCFF';
-   _elem();
+   ?>
+       <tr bgcolor="<?php echo $color; ?>">
+         <td><?php echo htmlspecialchars($user['name']); ?></td>
+         <td><?php echo $user['mail']; ?></td>
+       </tr>
+ <?php
  }

このような処理を行うためには、PHPでPHPコードを解析する必要があります。
しかしながら、そのようなライブラリは一向に見つかりません。

そもそも、「PHPでPHPを解析する」という意味を検索するためのキーワードすら捻り出せません。
「PHP PHPを解析」で検索しても、まるで無関係な内容がヒットしてしまい、検索すらままならない状況です。

PHPでPHPを解析するライブラリはありますか?
または、そのための方法は存在しますか?
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • 9walk

    2015/05/17 08:31

    質問の意図はテンプレートエンジンを自作することでしょうか?
    それともHTMLの生成が目的で、Kwartz以外によいテンプレートエンジンがあれば、それを使っても構わないと考えてもよいのでしょうか?

    キャンセル

  • sounisi5011

    2015/05/17 09:47

    テンプレートエンジンの自作です。

    キャンセル

回答 4

checkベストアンサー

+2

PHP で実装された PHP のパーサなら下記が有名です。うろ覚えですが AST が得られたと思います。

nikic/PHP-Parser

字句解析だけしか必要ないなら Tokenizer でも良いと思います。これは単にトークンのリストが得られたと思います。

PHP: Tokenizer - Manual

ただ、字句解析だけだと識別子(T_STRING トークン)がなんなのか直ちに特定できないので、質問にかかれているような用途だと難しいかもしれません。


参考までに、Smarty3 は下記の字句解析器/構文解析器ジェネレータが使われているそうです。

PHP_LexerGenerator
PHP_ParserGenerator

と思っていたんですが、いつの間にか fork?していたようでした。

smarty-php/smarty-lexer

独自形式のテキストファイル のパーサに使えたりするかもしれません。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/05/18 01:32

    いつも回答ありがとうございます。


    Tokenizerを試してみたところ、`{}`で囲まれた範囲のPHPコードを抽出する用途として使えそうな動作を示しました。
    文字列やヒアドキュメント、実行演算子、PHPタグの外やコメントなどが、種類ごとに適切に分けられた状態で取得できています。
    また字句解析であるためか、独自形式のファイルを直接指定してもエラーを出さずに動作しています。
    最大の懸念であったPHPコードの取得が簡単に実装できそうです。


    本題の「PHPでPHPを解析する」についても、nikic/PHP-Parserで処理できるかもしれません。
    実際に検証はしていないのですが、どうやら解析結果の編集、PHPコードへの再変換も可能なようで、今回の用途として適切であると考えます。


    今回、極めて有用な情報を入手できました。
    感謝します。

    キャンセル

-1

意味がよくわからないことがあります。
「独自形式のテキストファイルに記述された{}で囲まれた範囲のPHPコード」
とありますが、{}で囲まれた範囲のPHPコードは、sounisi5011さんのおっしゃるようにいろいろな意味で使われいますよね。
独自形式のテキストファイルということは、sounisi5011さんが意味を決めてPHPコードを{}を囲っていると思うのですけど、何のために囲っているのでしょうか?

私もPHPでキーワードを決めた部分を置き換えることをやっていますが、「PHPでPHPを解析する」なんてややこしいことはしていません。
置き換える文字列が複数ある場合、
・置き換える文字列をキーとした連想配列を記述とたファイルを作成します。
・そして、それぞれのキーに対応する置き換えられるPHPコードを文字列として記述して起きます。
・実行時に、このファイルをインクルードします。
・実行したいPHPファイルを読み込みます。
・読み込んたPHPファイルに置き換える文字列があったら、その文字列をキーとした連想配列に
記憶しているPHPコードを置き換えます。
・読み込んたPHPファイルを保存して実行します。
このようにして対応したことがあります。
私の頭では、なぜ、わざわざ、混乱するような内容のファイルで設計するのかが理解に苦しむところです。
sounisi5011さんが考えて、{}で囲ったPHPコードのファイルを導入されていると思いますので、参考にはならないとは思いますが・・・

sounisi5011さんがを設計段階から{}で囲ったPHPコードのファイルを導入れているのでしょうか?
また、{}で囲ったPHPコードのファイルは、どのようなフォーマットなのでしょうか?
教えいただけると嬉しいです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/05/17 05:06

    下記サイトは、Kwartzのユーザーガイドです。
    KwartzはRubyのツールですが、PHPにも対応しています。

    http://www.kuwata-lab.com/kwartz/kwartz3ruby-users-guide.02.html#table1.php.plogic

    ここの`table1.php.plogic`にて、`logic: {~}`の中にPHPコードを記述しています。
    この、記述されたPHPコードを取得し、さらに関数等の置換も試みたいというのが私の考えです。

    キャンセル

-2

table1.php.plogicのこのコードから'logic: {'以降のPHPを抽出するのは、簡単ですよ。
難しく考えすぎてはないでしょうか。

このコードですよね。
-------------------------------------
#row {
  attrs:  "bgcolor" $color;
  logic: {
    $i = 0;
    foreach ($list as $user) {
      $color = ++$i % 2 == 0 ? '#FFCCCC' : '#CCCCFF';
      _elem();
    }
  }
}
------------------------------------------------------
私の考えは、関数などの内容を分析をする必要はなく、{}は必ずどのような関数であろうとPHPは
入れ子構造ですから'{'に対応する'}'は一番最初に出てくるものです。
ですから、このようにすればいいと思います。
1.table1.php.plogicをファイルとして読み込み$fileに代入する
2.'logic:'をキーに$fileを$aと$bの2つに分ける。
 list($a,$b) = split('logic:',$file);
  これで$bには、
$b=' {
    $i = 0;
    foreach ($list as $user) {
      $color = ++$i % 2 == 0 ? '#FFCCCC' : '#CCCCFF';
      _elem();
    }
  }
}'
が代入されています。
3.$bの中の先頭よりの'{'より後がPHPコードなので、中の先頭よりの'{'以前を
削除し$bに代入する。
この時、先頭にスペースがある時とない時があるので考えてみてください。
4.$bの中に'{'がいくつあるか調べ$cに代入して置きます。
   $c = mb_substr_count($b, '{');
5.$b文字列を'}'を区切りに分解して$array配列に入れる。
$array = split('}',$b)
  実行すると
  $array[0]には、'$i = 0;
    foreach ($list as $user) {
      $color = ++$i % 2 == 0 ? '#FFCCCC' : '#CCCCFF';
      _elem();
    ';
$array[1]には、'  ';
$array[2]には、'';
 それぞれ入ります。

6.つまり、先に'{'の数を調べ$cに代入してあります。
$cが0であれば、'{'はなかったということですから、$php = $array[0]
$cが1であれば $array[1]以前がphpコードであるので、$php ="$array[0].}"
$cが2であれば $array[2]以前がphpコードであるので、$php ="$array[0].}.$array[1].}"
$cが3であれば 同様に $php ="$array[0].}.$array[1].}.$array[2].}"
という具合で抽出できます。
関数のコードが決まっていれば、先ほどの方法で置き換えできるのではないでしょうか?
いかがでしょうか

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/05/17 09:46

    `{}`が常にネスト構造であるならば問題ないのですが、事はそう単純ではありません。
    例えば文字列の中に、無関係な`{}`が現れてしまったらどうなるでしょう?

    PHPの文字列には、引用符で囲まれたものとヒアドキュメントが存在します。
    引用符であれば正規表現で除外する事は可能です。
    しかし、ヒアドキュメントのような構造はこの限りではありません。
    さらに、他の文字列表現として、PHPタグの存在があります。

    文字列以外にも、PHPコード内で`{}`を無関係に含められる構文が存在するかもしれません。
    私の最大の懸念はここです。
    よって、PHPのパーサーを使用したほうが確実と考えました。

    キャンセル

-2

ことを難しく考えすぎているように思います。
>PHPの文字列には、引用符で囲まれたものとヒアドキュメントが存在します。
確かにその通りですが、関数に以外に、引用符で囲まれた文字定数とヒアドキュメントしかないのです。たくさんあるとさんあると思い込んでいませんか?

考えは単純です。文字定数とヒアドキュメントを探してその中にある{'と'}の数を数えておけば問題なく足し算と引き算で先ほどのアルゴリズムで問題なく抽出できますよ。
アルゴリズムがわかっているのですから、プログラム出来るはずです。

それ以外の所に{'や'}があったら、エラーで停止するはずです。元々、PHPを抽出するソースは、エラーがないものとして考えないと、事は進みません。
先ほどの私のアルゴリズムは文字定数やヒアドキュメントに現れたとしても、{'の数を数え、その数分の消した'}を元の位置に置いて抽出するPHPコードに組み直しているので、そのアルゴリズムで問題なく抽出できます。

'}`をもとの位置に戻す数を計算します。
{'の数から文字定数やヒアドキュメント内の{'の数を引いて、
関数に使用されている`{'の数を出す。
文字定数やヒアドキュメント内の'}の数に関数に使用されている{'の数を足した足したものが'}`をもとの位置に戻す数です。

私の答えも100%ではないと思っていますし、sounisi5011さんの考えの方が優れている
かも知れません。
ダメだと否定していると、人間、思考停止しますから、それ以上考えることをやめて
何も進まなくなりますよ。ダメと思われる中に、ヒントが見つかるかもしれません。
一度、プログラムを作っていろいろなケースで試してみるたらいかがでしょうか?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/05/17 14:43

    > 関数に以外に、引用符で囲まれた文字定数とヒアドキュメントしかないのです。たくさんあるとさんあると思い込んでいませんか?

    質問本文に実行演算子について記載してあることに気が付きましたか?
    実行演算子は、文字列のように記述することで任意のコマンドを実行できます。
    このコマンドの中にも`{}`は含まれる可能性があります。
    この時点で、この指摘は誤りです。

    > 考えは単純です。文字定数とヒアドキュメントを探してその中にある`{'と'}`の数を数えておけば問題なく足し算と引き算で先ほどのアルゴリズムで問題なく抽出できますよ。

    文字列内の`{}`は必ずしもネスト構造を取っているわけではありません。
    文字列内の`{}`も数えていた場合、"{{{{{{{{{{{{{"なんていう文字列があったら途端に破綻します。
    もっとも、この下に記載してあるように…

    > `{`の数から文字定数やヒアドキュメント内の`{`の数を引いて、
    関数に使用されている`{`の数を出す。
    > 文字定数やヒアドキュメント内の`}`の数に関数に使用されている`{`の数を足した足したものが`}`をもとの位置に戻す数です。

    文字列やヒアドキュメント等に含まれる`{}`をカウントから外せば、確かに動作するでしょう。
    しかし、ここが最大の問題点なのです。ここが解決できないためパーサに頼ろうとしています。

    文字列やヒアドキュメントなど、`{}`のカウントとして無視すべき構文(PHPの処理構造とは無関係に、`{}`を自由に含められる構文)を全て把握していないのです。
    私が知っている範囲でも、引用符で囲った文字列・ヒアドキュメント・Nowdoc・実行演算子・PHPタグ・コメント、これだけあります。
    これ以外に存在しないという確信が持てません。

    この点を把握することさえできれば、カウント以外に正規表現などの手法も検討できます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.35%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • PHP

    25496questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。