PHP 原則のオペコードの深い理解 · 著者: laruence( http://www.laruence.com/)
· この記事の URL: http://www.laruence.com/2008/06/18/221.html
私は最近、Yahoo の同僚に PHP と Apache の内部メカニズムについて講義をしなければなりませんでしたこの記事は、Sara Golemon の OPcode の理解に基づいています
オペコードは、Java の ByteCode や と同じように、PHP スクリプトによってコンパイルされる中間言語です。 NET の MSL など。 たとえば、次の PHP コードを記述した場合:
echo "Hello World"; $a = 1 + 1; echo $a;
PHP は、このコードを実行するために次の 4 つの手順を実行します (正確には、 PHP Zend の言語エンジン)
1. スキャン (レクシング)、PHP コードを言語フラグメント (トークン) に変換します
2. 解析、トークンを単純で意味のある式に変換します
3. コンパイル、式を Opocdes にコンパイルします
4. 実行。オペコードを一度に 1 つずつ順番に実行し、PHP スクリプトの機能を実現します。
注: APC などの一部のキャッシュでは、PHP がオペコードをキャッシュできるようになりました。これにより、リクエストが届くたびに最初の 3 つの手順を繰り返す必要がなくなり、PHP の実行速度が大幅に向上します。
それでは、Lexing とは何でしょうか? コンパイルの原理を学習した学生は、Lex は字句分析の基礎テーブルであることを理解しているはずです。 Zend/zend_ language_scanner.c は、Zend/zend_ language_scanner.l (Lex ファイル) を元に入力された PHP コードを字句解析し、「単語」を 1 つずつ取得する機能です。 PHP コードの一部をスキャンしてトークンに変換することについて
この関数を使用して最初に説明した PHP コードを処理すると、次の結果が得られます:
Array( [0] => Array ( [0] => 367 [1] => Array ( [0] => 316 [1] => echo ) [2] => Array ( [0] => 370 [1] => ) [3] => Array ( [0] => 315 [1] => "Hello World" ) [4] => ; [5] => Array ( [0] => 370 [1] => ) [6] => = [7] => Array ( [0] => 370 [1] => ) [8] => Array ( [0] => 305 [1] => 1 ) [9] => Array ( [0] => 370 [1] => ) [10] => + [11] => Array ( [0] => 370 [1] => ) [12] => Array ( [0] => 305 [1] => 1 ) [13] => ; [14] => Array ( [0] => 370 [1] => ) [15] => Array ( [0] => 316 [1] => echo ) [16] => Array ( [0] => 370 [1] => ) [17] => ;)
この返された結果を分析すると、次のことがわかります。ソースコード内の文字列、文字とスペースは変更されずに返されます。各ソース コード内の文字は、対応する順序で表示されます。ただし、タグ、演算子、ステートメントなどの他の項目は、トークン ID (つまり、T_ECHO、T_STRING など、Zend 内のトークンを変更するための対応するコード) と元のコードの 2 つの部分を含む配列に変換されます。ソースコード。
次に、解析段階になります。解析では、まずトークン配列内の余分なスペースが破棄され、次に残りのトークンが 1 つずつ単純な式に変換されます
1. 定数文字列をエコーします
2. 2 つの数値を加算します
3. 前の式の結果を変数に保存します
4. 変数をエコーします
次に、コンパイルステージが変更され、各 op_arrayd には次の 5 つの部分が含まれます。 o 1. オペコード番号の識別。ADD、Echo
など、各 OP_ARAY の操作のタイプを示します。 2. 結果 OPCODE の結果を保存します
3. 操作 1 から OPCODE
オペランド 2
5. 拡張値。オーバーロードされた演算子を区別するために使用される 1 つの整数
たとえば、PHP コードは次のように解析されます:
ZEND_ECHO 'Hello World' ZEND_ADD ~0 1 1 ZEND_ASSIGN !0 ~0 ZEND_ECHO !0
はは、$ はどこに行ったのか疑問に思うかもしれません。前?これを導入する操作の数が必要です。各操作は以下の 2 つの部分で構成されます:A) OP_TYPE: IS_CONST、is_tmp_var、is_var、is_unused、または is_cv
b) u、コンソーシアムによると異なるOP_TYPE、演算数の値(const)または左の値(var) op_array の結果このタイプのオペランドの u は、変数テーブルを指すハンドル (整数) を格納します ( ~0 など)。変数内の未知の一時変数 0 を表します。 table
IS_VAR これは変数の一般的な意味であり、$
で始まります
IS_CV は、ZE2.1/PHP5.1 以降のコンパイラで使用されるキャッシュ機構を表します。この変数は、変数が初めて参照されるときに CVd されるため、その変数のアドレスが格納されます。今後この変数を参照するためにアクティブなシンボル テーブルを再度検索するには、CV 変数が! で始まります。始まりはそれを示しています。
$a は参照されていないため、!0 に最適化されているようです。