現在、関数の勉強をしておりまして、理解を深めるためにオペコードレベルでどのように処理されているのかを調べております。
「PHPはどのように動くのか ~PHPコアから読み解く仕組みと定石」を読みながら vld の拡張ライブラリを入れてオペコードの確認をしております。
オペコードの表記等について不明な点があるので、教えてください。
質問が多いため、わかる箇所だけでも回答いただけると幸いですm(__)m
また、一言二言で説明できないよってときは参考サイトを教えて頂けると嬉しいです。
下記のfunc1.php
記述のオペコードを表示しました。
私はWindowsのPHP5.6のローカル環境で確認しております。
php
1<?php 2function a() 3{ 4 $count = 0; 5 return function() use (&$count) { 6 return ++$count; 7 }; 8} 9 10$b = a(); 11echo $b(); 12echo $b(); 13echo $b();
line # * op fetch ext return operands --------------------------------------------------------------------------------- 2 0 > NOP 10 1 DO_FCALL 0 $0 'a' 2 ASSIGN !0, $0 11 3 INIT_FCALL_BY_NAME !0 4 DO_FCALL_BY_NAME 0 $2 5 ECHO $2 12 6 INIT_FCALL_BY_NAME !0 7 DO_FCALL_BY_NAME 0 $3 8 ECHO $3 13 9 INIT_FCALL_BY_NAME !0 10 DO_FCALL_BY_NAME 0 $4 11 ECHO $4 12 > RETURN 1
line # * op fetch ext return operands --------------------------------------------------------------------------------- 2 0 > NOP 10 1 DO_FCALL 0 $0 'a' 2 ASSIGN !0, $0 11 3 INIT_FCALL_BY_NAME !0 4 DO_FCALL_BY_NAME 0 $2 5 ECHO $2 12 6 INIT_FCALL_BY_NAME !0 7 DO_FCALL_BY_NAME 0 $3 8 ECHO $3 13 9 INIT_FCALL_BY_NAME !0 10 DO_FCALL_BY_NAME 0 $4 11 ECHO $4 12 > RETURN 1
line # * op fetch ext return operands --------------------------------------------------------------------------------- 4 0 > ASSIGN !0, 0 5 1 DECLARE_LAMBDA_FUNCTION '%00%7Bclosure%7DC%3A%5Cxampp%5Chtdocs%5Cfunc1.php029DCEDC' 7 2 > RETURN ~1 8 3* > RETURN null
#【質問1】「ローカル変数」「一時的な変数」「一時的ではない変数」の違いは?
「PHPはどのように動くのか ~PHPコアから読み解く仕組みと定石」には! ~ $
に関して下記のように解説しています。
!1、~2、$3という文字 = それぞれ内部的な変数
!<数字> = ローカル変数
~<数字> = 一時的な変数
$<数字> = 一時的ではない変数
「ローカル変数」「一時的な変数」「一時的ではない変数」はどのような変数のことなのでしょうか?
推測ですが、「ローカル変数」は、関数内に記述した変数のことで、「一時的な変数」は静的変数のことなのかなという感じですが、「一時的ではない変数」については皆目検討もつきません。
#【質問2】029DCEDCの意味は?
ダンプしたオペコードのoperandsに %00%7Bclosure%7DC%3A%5Cxampp%5Chtdocs%5Cfunc1.php029DCEDC
とあります。
パーセントエンコーディングのため一つ一つ変換すると NULL{closure}C:\xampp\htdocs\unc1.php029DCEDC
になるかと存じます。
最後の 029DCEDC
だけ何の記述で何を示しているのかわかりません。
これは何の記述でしょうか?
#【質問3】* と ext の意味は?
vldでオペコードダンプすると、番号の左側に * が表示されます。
この * はどのような意味でしょうか?
ダンプした列に ext という項目がありますが、これはどのような意味でしょうか?
#【質問4】two-pass compiler
下記サイトにphpは two-pass compiler との記述があります。
※まだ英語を習得できていないので英字サイトの内容を正しく理解できておりません。すいません><
私の理解しているPHPの内部処理を図示しました。
図示した通り、PHP5とPHP7ではオペコードの作成方法が異なるかと存じます。
ここから質問です。
###【質問4-1】two-pass compiler
two-pass compiler についてググってもあまり情報がないのですが、下記のような動作をしているということでよろしいのでしょうか?
調べてみると、PHPのコンパイラはtwo-passのコンパイラ、つまり2回ソースをスキャンするタイプのコンパイラなんです。 1回目で関数の宣言とかそういうのをスキャンして、2回目で実際の関数の呼び出しのopcodeを生成しているようです。
引用:PHPをハックしよう(第二回) | IT特殊案件ならBackflip180
###【質問4-2】PHP5とPHP7での違いは?
図示した通り、PHP5とPHP7ではオペコードの作成方法が異なるかと存じます。
PHP5はパーサーが two-pass で、PHP7からはオペコードコンパイラが two-pass なのでしょうか?
ご存知の方いれば、何卒ご教示くださいm(__)m
#参考・閲読サイト
PHPの内部処理を理解するために下記のサイトを閲読しました。
※閲読しましたが、理解できていないところも多々あります^^;
- PHP7の内部実装から学ぶ性能改善テクニック
- ZendEngine勉強会で「拡張ライブラリでなるべく簡単に構文を追加する方法」というタイトルで喋ってきました
- PHP AST 徹底解説
- PHP プログラムのファイルサイズと抽象構文木のノード数の分布
- PHP7調査(2)コンパイル時にASTを構築するようになった
- PHP実行までの流れとOPcache
- オレオレPHPのつくり方
- PHP による hello world 入門
- PHP 5.5ネーティブキャッシュの話
- Zend OPcacheの速さの秘密を探る
#【追記】調査メモ
質問後に調査した結果をここにフィードバックします。
C言語も英語も読めない未熟者ですので、私の調査結果は信憑性に欠けると思います。
そのときは、ご指摘くださいm(__)m
ダンプした ext について
vld の表示は zend_compile.h の下記の箇所をダンプしているはずです。
struct _zend_op { const void *handler; znode_op op1; znode_op op2; znode_op result; uint32_t extended_value; uint32_t lineno; zend_uchar opcode; zend_uchar op1_type; zend_uchar op2_type; zend_uchar result_type; };
ext という項目は uint32_t extended_value;
に該当するかと思います。
extended_value
というワードで調べたら PHP による hello world 入門 に下記の説明がありました。
ZEND_INCLUDE_OR_EVAL 命令は名前の通り include / require の他に eval にも対応しているのですが、命令列のダンプ結果にはこれらを区別する情報がないのを不思議に思うかもしれません。これは phpdbg の問題です。実際には一部の命令は、2 つのオペランドの他に extended_value というデータをとる場合があり、PHP 5.6 の phpdbg は ZEND_INCLUDE_OR_EVAL 命令の extended_value の表示に対応していないようです。vld だと extended_value での違いもちゃんと表示してくれます。
zend_opに関して Phpをいじり倒す10の方法 に説明がありました。
ただ、extended_value が現時点で何なのかよくわかってません^^;
参考になるものを見つけたら追記します。
ダンプした * について
More source analysis with VLD に下記の記述があります。
Every opcode that has a * after the number (like in 5*) is code that can not be reached, and can possibly be eliminated from the oparrays in an optimiser.
英語読めないので、Google先生に頼ると到達できていないコードのようです。
番号の後に*(5 *のように)があるすべてのオペコードは、到達できないコードであり、オプティマイザのoparraysから削除される可能性があります。
一般的なソフトも未保存のファイルに * が付くのでGoogle先生の解釈で概ね間違いない気がします。
op_arrayに関しては PHP による hello world 入門 に下記の説明があります。
PHP ソースコードのバイトコードへのコンパイル結果は、関数ごと別々の配列へ格納されます。コンパイル結果の命令列を保持する配列は op_array と呼ばれています。phpdbg の print 命令はこの op_array の内容をダンプするものです。
基本的に op_array に格納されるようですが、英語読めないのでどのタイミングでいつ削除されるのかなど肝心なところが全くわかりません^^;
** ※teratailの質問は、上限が10000文字で追記できないので、他の調査メモは回答へ追記します。 **
** ※この質問をクリップしている方もいるため、調査メモを追記してきましたが、文字数制限で回答等にも記載し、読みにくいため、理解できたら記事をまとめてQiitaに投稿します。**
回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/11/08 07:31 編集
2016/11/10 04:17