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

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

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

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

Q&A

解決済

2回答

4190閲覧

PHPのオペコードについて教えてください

7968

総合スコア253

PHP

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

6グッド

8クリップ

投稿2016/11/08 03:46

編集2016/11/10 04:36

現在、関数の勉強をしておりまして、理解を深めるためにオペコードレベルでどのように処理されているのかを調べております。
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の内部処理を理解するために下記のサイトを閲読しました。
※閲読しましたが、理解できていないところも多々あります^^;

#【追記】調査メモ

質問後に調査した結果をここにフィードバックします。
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に投稿します。**

tanat, mhashi, wakame_taishi, yodel, Y.H., ikuwow👍を押しています

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

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

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

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

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

guest

回答2

0

ベストアンサー

PHPのコアを呼んだことがありますが、自分も全然理解していないので、全部推察程度です。。。
PHPのコアのソース呼んだほうが早いかもですね。。。
個人的にはかなり高レベルの質問な気がするので、回答つくの難しいかもですね(・_・;)

【質問1】「ローカル変数」「一時的な変数」「一時的ではない変数」の違いは?
ローカル変数:クラス等のオブジェクト無いで使用するレベルの変数
一時的な変数:関数内でのみ存在する変数
一時的ではない変数:グローバル変数(もしかしたらphp.iniに設定されるような値のことかも?)

PHP

1$val1 = "グローバル変数"; 2class Test { 3 $val2 = "ローカル変数"; 4 5 function test() { 6 $val3 = "一時的な変数"; 7 } 8}

【質問2】029DCEDCの意味は?
コンパイル後の一時ファイル名では??

お恥ずかしいながら他は全然分かんないです。
PHP5とPHP7はオブジェクト構造が違うくらいしか知らないです。

投稿2016/11/08 06:34

編集2016/11/08 06:39
himakuma

総合スコア952

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

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

7968

2016/11/08 07:31 編集

回答ありがとうございます。 やはり、PHP自体のソースで確かめるのが一番なんですね。 C言語も読めない未熟者ですので、読めるように研鑽します>< ご回答頂いた変数の違いを頼りにしてダンプして確かめてみたいと思います^^ 029DCEDCもダンプする度に変わるので、ご回答の通り、一時ファイルかもしれません。 参考になりました。ありがとうございましたm(__)m
7968

2016/11/10 04:17

この質問をクリップしている方もいるため、調査メモを追記してきましたが、文字数制限で回答等にも記載し、読みにくいため、理解できたら記事をまとめてQiitaに投稿します。 お陰様で理解が進みました。 ありがとうございましたm(__)m
guest

0

調査メモの続き:teratailの質問は、上限が10000文字で質問には追記できないので回答に追記します。

#【追記1】

様々な変数をダンプしてみました。

<?php /* グローバル変数 */ $a = 1; $b = 2; echo $a + $b; /* ローカル変数 */ function alpha() { $a = 'abc'; return $a; } echo alpha(); /* 静的プロパティ */ class Beta { public static $a = 'xyz'; } echo Beta::$a; /* インスタンスプロパティ */ class Gamma { public $a = 'efg'; } $c = new Gamma; echo $c->a;
compiled vars: !0 = $a, !1 = $b, !2 = $c line # * op fetch ext return operands --------------------------------------------------------------------------------- 3 0 > ASSIGN !0, 1 4 1 ASSIGN !1, 2 6 2 ADD ~2 !0, !1 3 ECHO ~2 9 4 NOP 13 5 DO_FCALL 0 $3 'alpha' 6 ECHO $3 16 7 NOP 19 8 FETCH_R static member $5 'a' 9 ECHO $5 22 10 NOP 26 11 FETCH_CLASS 0 :7 'Gamma' 12 NEW $8 :7 13 DO_FCALL_BY_NAME 0 14 ASSIGN !2, $8 27 15 FETCH_OBJ_R $11 !2, 'a' 16 ECHO $11 17 > RETURN 1
compiled vars: !0 = $a line # * op fetch ext return operands --------------------------------------------------------------------------------- 10 0 > ASSIGN !0, 'abc' 11 1 > RETURN !0 12 2* > RETURN null

3つの変数の意味は一般的には himakuma さん の回答した定義かと存じます。
表示から推察した結果は下記の通りです。
書籍の定義とは異なるようでして、謎が深まるばかりです。

記号意味
!グローバル変数?
~計算結果?(一時的な変数と呼んでいいのかな?)
$ローカル変数?

様々な変数をダンプしたら、新たに : という記号が出てきました
オペコード上ではインスタンスを作成するのにいくつか手順を踏むみたいです。
まず、11 FETCH_CLASSGamma というクラスを取得し、 :7 を返しています。
次に new Gamma を処理しているようですが、先ほどの :7 の返り値を指定することで、$8というローカル変数的な何かが返ってくるようです。
何と形容すればよいのかわかりませんが、: はクラスを取得するときに返ってくる"何か"のようです。

#【追記2】

! $ ~ について参考になるものを見つけたので、追記します。

OpenOfficeのファイルですが、phpopcodes_aug2008 にVLDに関しての記述があります。下記が引用です。

! == compiler variable

$ == variable
~ == temporary

この3つについて 第三回闇PHP勉強会開催した&PHPカンファレンスとPHPMatsuriで喋った に説明がありました。下記が引用です。

ZendEngine内部で使われる変数の種類には以下の3つがあります。

Variable 通常のPHPの変数
Temporary variable ZendEngineないで利用される変数
Compiled variable ?

このうち、最初のVariableはPHPの$hogeみたいな通常の変数のことで、その次のTemporary VariableはZendEngine内部でのみ利用されるレジスタのような変数ということがわかっていたのですが、三番目のCompiled Variableというのが何のことがよくわかっていませんでした。
これなんなのかというと、通常のPHPの変数と同じものなんですが、$hogeみたいなPHPの変数はZendEngineのハッシュテーブルの中で管理されているのですが、ハッシュテーブルなので当然格納するときは変数名がハッシュ化されます。Compiled Variableとは、実行時に変数名をハッシュ化してオーバーヘッドにならないようにコンパイル時に予めハッシュ化されるPHPの変数ということがコードを読んでわかりました。
確かにPHPの変数名は実行時にならないとわからない場合もありますが、$hogeみたいなコードの場合はコンパイル時に変数名もわかっているわけなので予め変数名をハッシュ化しておいたほうがオーバーヘッドが少ないということなんでしょう。

まとめると下記のような感じかなと思います。(自信なし^^;)

記号用語意味
!Compiled variableハッシュ化された変数
~Temporary variableZendEngine内で利用される変数
$Variable通常の変数

#【追記3】

別の質問で変数値や即値に対応するzvalやHashTableはオペコード作成時またはオペコード実行時に作成されると教えて頂きました。

何の根拠もありませんが、オペコード作成時に確定できる変数が ハッシュ化された変数 ではないかと考えております。例えば、$a = 1というのはオペコード作成時に確定できるため、!0となっているのかと思います。オペコード実行時にしか確定できないのは、計算結果などです。$a + $bのような計算結果は~2となっています。オペコード実行時に計算され、そのときに確定するので、このような変数が ZendEngine内で利用される変数 ではないかと思います。他に 普通の変数 というのがありますが、いまいちわかっておりません。以上、憶測というか妄想です。

投稿2016/11/10 04:12

編集2016/11/22 04:08
7968

総合スコア253

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問