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

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

新規登録して質問してみよう
ただいま回答率
85.49%
PHP

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

Q&A

解決済

4回答

5707閲覧

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

sounisi5011

総合スコア697

PHP

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

0グッド

3クリップ

投稿2015/05/16 15:51

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

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

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

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

例えば、関数_elemの実行箇所を置き換える場合、以下のようになります:

lang

1$i = 0; 2foreach ($list as $user) { 3 $color = ++$i % 2 == 0 ? '#FFCCCC' : '#CCCCFF'; 4 _elem(); 5}

lang

1$i = 0; 2foreach ($list as $user) { 3 $color = ++$i % 2 == 0 ? '#FFCCCC' : '#CCCCFF'; 4 ?> 5 <tr bgcolor="<?php echo $color; ?>"> 6 <td><?php echo htmlspecialchars($user['name']); ?></td> 7 <td><?php echo $user['mail']; ?></td> 8 </tr> 9<?php 10}

関数_elemの実行箇所を、別のPHPコードで置き換えています。

lang

1 $i = 0; 2 foreach ($list as $user) { 3 $color = ++$i % 2 == 0 ? '#FFCCCC' : '#CCCCFF'; 4- _elem(); 5+ ?> 6+ <tr bgcolor="<?php echo $color; ?>"> 7+ <td><?php echo htmlspecialchars($user['name']); ?></td> 8+ <td><?php echo $user['mail']; ?></td> 9+ </tr> 10+ <?php 11 }

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

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

PHPでPHPを解析するライブラリはありますか?
または、そのための方法は存在しますか?

気になる質問をクリップする

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

9walk

2015/05/16 23:31

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

2015/05/17 00:47

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

回答4

0

ベストアンサー

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

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

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


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

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

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

投稿2015/05/17 06:01

編集2015/05/17 06:30
ngyuki

総合スコア4514

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sounisi5011

2015/05/17 16:32

いつも回答ありがとうございます。 Tokenizerを試してみたところ、`{}`で囲まれた範囲のPHPコードを抽出する用途として使えそうな動作を示しました。 文字列やヒアドキュメント、実行演算子、PHPタグの外やコメントなどが、種類ごとに適切に分けられた状態で取得できています。 また字句解析であるためか、独自形式のファイルを直接指定してもエラーを出さずに動作しています。 最大の懸念であったPHPコードの取得が簡単に実装できそうです。 本題の「PHPでPHPを解析する」についても、nikic/PHP-Parserで処理できるかもしれません。 実際に検証はしていないのですが、どうやら解析結果の編集、PHPコードへの再変換も可能なようで、今回の用途として適切であると考えます。 今回、極めて有用な情報を入手できました。 感謝します。
guest

0

ことを難しく考えすぎているように思います。

PHPの文字列には、引用符で囲まれたものとヒアドキュメントが存在します。

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

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

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

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

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

投稿2015/05/17 03:11

KazutoshiOhashi

総合スコア125

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sounisi5011

2015/05/17 05:43

> 関数に以外に、引用符で囲まれた文字定数とヒアドキュメントしかないのです。たくさんあるとさんあると思い込んでいませんか? 質問本文に実行演算子について記載してあることに気が付きましたか? 実行演算子は、文字列のように記述することで任意のコマンドを実行できます。 このコマンドの中にも`{}`は含まれる可能性があります。 この時点で、この指摘は誤りです。 > 考えは単純です。文字定数とヒアドキュメントを探してその中にある`{'と'}`の数を数えておけば問題なく足し算と引き算で先ほどのアルゴリズムで問題なく抽出できますよ。 文字列内の`{}`は必ずしもネスト構造を取っているわけではありません。 文字列内の`{}`も数えていた場合、"{{{{{{{{{{{{{"なんていう文字列があったら途端に破綻します。 もっとも、この下に記載してあるように… > `{`の数から文字定数やヒアドキュメント内の`{`の数を引いて、 関数に使用されている`{`の数を出す。 > 文字定数やヒアドキュメント内の`}`の数に関数に使用されている`{`の数を足した足したものが`}`をもとの位置に戻す数です。 文字列やヒアドキュメント等に含まれる`{}`をカウントから外せば、確かに動作するでしょう。 しかし、ここが最大の問題点なのです。ここが解決できないためパーサに頼ろうとしています。 文字列やヒアドキュメントなど、`{}`のカウントとして無視すべき構文(PHPの処理構造とは無関係に、`{}`を自由に含められる構文)を全て把握していないのです。 私が知っている範囲でも、引用符で囲った文字列・ヒアドキュメント・Nowdoc・実行演算子・PHPタグ・コメント、これだけあります。 これ以外に存在しないという確信が持てません。 この点を把握することさえできれば、カウント以外に正規表現などの手法も検討できます。
guest

0

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/16 21:42

KazutoshiOhashi

総合スコア125

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sounisi5011

2015/05/17 00:46

`{}`が常にネスト構造であるならば問題ないのですが、事はそう単純ではありません。 例えば文字列の中に、無関係な`{}`が現れてしまったらどうなるでしょう? PHPの文字列には、引用符で囲まれたものとヒアドキュメントが存在します。 引用符であれば正規表現で除外する事は可能です。 しかし、ヒアドキュメントのような構造はこの限りではありません。 さらに、他の文字列表現として、PHPタグの存在があります。 文字列以外にも、PHPコード内で`{}`を無関係に含められる構文が存在するかもしれません。 私の最大の懸念はここです。 よって、PHPのパーサーを使用したほうが確実と考えました。
guest

0

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

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

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

投稿2015/05/16 19:07

KazutoshiOhashi

総合スコア125

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sounisi5011

2015/05/16 20: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コードを取得し、さらに関数等の置換も試みたいというのが私の考えです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問