PHPにおける接頭辞の自己増加(++i)と接尾辞の自己増加(i++)

5029 ワード

最近、筆記試験の人車PHPで次のような問題をしました.
$i = 0;
$i = $i++;
echo $i;

その时、自分はためらうことなく1を記入して、それから検索を思い出して、自分がどうして面接の通知を受け取れない原因を知っていました.以下は転載です.一時変数に1を加えた結果ではなく、一時変数を返します.
私たちが最初の言語を勉強するとき、例えば大学の課程の中のC言語のプログラム設計は、接頭辞の自己増加(++i)と接尾辞の自己増加(i++)に悩まされたことがあるかもしれません.分かったと思った.
i++:まず参照してから増加し、まずiが存在する式でiの現在の値を使用し、その後iに1++iを追加させます:まず参照を追加し、iに1を追加させ、それからiが存在する式でiの新しい値を使用するという表現は基本的に間違いなく、正確ではないとしか言えません.『Expert C Programming』という本の付録には、++iはiのアドレスを取り、その内容を増やしてレジスタに値を置くことを示す.i++はiのアドレスを取り、その値をレジスタに読み込み、メモリのiの値を増やすことを表す.ここのレジスタは、式で使用する値を格納します.
PHPにも++iとi++がありますが、Zendカーネルはどのようにしてこの2つの自己増加方式を実現しているのでしょうか.次の例を見て、このコードを実行しない場合、何が出力されると思いますか?
$i = 0;
$i = $i++;
echo $i;

答えが何であるかは関係ない.Zendカーネルから直接,この自己増分動作の実装を確認した.
VLDを使用して、i++および++iを含むPHPコードによって生成された中間コードを表示します.
$i = 0;
$i++;
++$i;

VLDコマンド(php-dvld.active=1-dvld.verbosity=3 t.php)を使用して、詳細パラメータを表示します.
number of ops:  8
compiled vars:  !0 = $i
line     # *  op                           fetch          ext  return  operands
--------------------------------------------------------------------------------
-
   2     0  >   EXT_STMT                                          RES[  IS_UNUSED  ]         OP1[  IS_UNUSED  ] OP2[  IS_UNUSED  ]
         1      ASSIGN                                                    OP1[IS_CV !0 ] OP2[ ,  IS_CONST (0) 0 ]
   3     2      EXT_STMT                                          RES[  IS_UNUSED  ]         OP1[  IS_UNUSED  ] OP2[  IS_UNUSED  ]
         3      POST_INC                                          RES[  IS_TMP_VAR ~1 ]       OP1[  IS_CV !0 ]
         4      FREE                                                      OP1[IS_TMP_VAR ~1 ]
   4     5      EXT_STMT                                          RES[  IS_UNUSED  ]         OP1[  IS_UNUSED  ] OP2[  IS_UNUSED  ]
         6      PRE_INC                                                   OP1[IS_CV !0 ]
   5     7    > RETURN                                                    OP1[IS_CONST (0) 1 ]

branch: #  0; line:     2-    5; sop:     0; eop:     7
path #1: 0,

VLD拡張の出力情報から分かるように、プレフィックス自己増加(++i)に対応するopcodeはPREINC、接尾辞自己増加(i++)に対応するopcodeはPOST_INC. まず,接頭辞が自己増加(++i),++iが戻り値を持たない,あるいはその戻り値が空であることを見る.中間コードとVLDで表示されるOP 1のパラメータタイプによって、++$iの中間コードが実行されるときに最終的に呼び出されるのはZend/zend_であることがわかります.vm_execute.hファイルのZEND_PRE_INC_SPEC_CV_HANDLER関数.ZEND_PRE_INC_SPEC_CV_HANDLER関数にはいくつかのキーがあります.
CVタイプ変数の取得、呼び出し_get_zval_ptr_ptr_cv CVタイプ変数を取得します.ここでのCVタイプの変数は、PHPコンパイル中のキャッシュと同様の役割であり、主な役割は、いくつかの変数の記憶速度を向上させることである.increment_function関数は、インスタンス変数、クラス変数、または通常の変数にかかわらず、最終的にincrement_を呼び出します.function関数は変数の増加操作を実現する.この関数では、PHP 5において、プログラムは変数の種類によって異なる処理を行う.3.1このバージョンでは、PHPはISをサポートしています.LONG、IS_DOUBLE、IS_NULLとIS_STRINGの4種類.変数のタイプがIS_の場合NULL、プログラムは変数の値を1に割り当てます.変数タイプが文字列の場合、プログラムはそれを整形または浮動小数点型に変換して計算します.RETURN_の使用VALUE_UNUSEDマクロは結果をクリアし、このマクロの役割はresult変数のタイプをEXT_に設定することです.TYPE_UNUSEDタイプ.プレフィックス自己増分(++$i)動作はZendカーネルでは本質的に動作変数そのものであり,式でもこの変数そのものが用いられる.
++iの実装を理解し,より多くのi++操作を使用する可能性のある実装を見た.同様に、中間コードPOST_からINCとOP 1のタイプはIS_CV、Zend/zend_vm_execute.hファイルに実装されているZEND_が見つかりましたPOST_INC_SPEC_CV_HANDLER. 前のZEND_とPRE_INC_SPEC_CV_HANDLERは、CVタイプ変数を取得するプロセスとincrement_function関数は変数値を増加させるプロセスですが、それ以外に1つの操作が多くなり、同時に1つの操作も少なくなります.多くの操作は次のとおりです.
EX_T(opline->result.u.var).tmp_var = **var_ptr;
zendi_zval_copy_ctor(EX_T(opline->result.u.var).tmp_var);

この2行のコードの役割は,戻り値を一時変数に初期化し,元のiの値をここに格納することであり,これが生成した中間コードをVLDを用いて先に確認した結果,RES[ISTMPVAR 1]となった理由である.この初期化が完了すると、プログラムは増加操作を継続し、増加操作が完了すると終了し、以前の++i操作ではresultをUNUSEDタイプに設定します.これが少ない操作です.
接尾辞自己増加($i++)式では、一時変数に格納された元の変数値が使用され、変数自体の値が増加します.PHPにおけるこのような変数の分離は,一時変数+戻り値によって解決される.
ここでは、最初の質問に答えることができます.0を出力します.式ではi++の戻り値は一時変数、すなわちiの元の値、すなわち0であるからである.