各 php5.5 変数は、zval と呼ばれる変数コンテナーに保存されます。
zval 変数コンテナには、変数の型と値に加えて、2 バイトの追加情報も含まれます。
1. 1つ目は「is_ref」で、bool型で、この変数が参照セットに属しているかどうかを識別するために使用され、属している場合は値が1、そうでない場合は0です。
この変数を使用すると、php エンジンは通常の変数と参照変数を区別できます。
2. 2つ目は「refcount」で、このzval変数(シンボル)を指すポイントの数を示すために使用されます。すべてのシンボルにはスコープがあり、メインのスクリプトや関数、メソッドにもスコープがあります。
すべてのシンボルはシンボル テーブルに存在します。
変数に定数値が割り当てられると、次の例のように zval 変数コンテナーが生成されます。
$a = "Hello world";
?>
このとき、次のプログラムを実行して、zval コンテナ内の is_ref と refcount の値を指す $a 変数を取得します
$a = "Hello world";
print_r(xdebug_debug_zval('a'));
?>
a: (refcount=1, is_ref=0)='Hello world'
次に、参照代入と通常代入を調べるために次の実験を行います。
まず、次のように $b が $a を指すようにし、is_ref、refcount を確認します。
$a = "こんにちは"
;
$b = $a;print_r(xdebug_debug_zval('a'));
print_r(xdebug_debug_zval('b'));
?>
a: (refcount=2, is_ref=0)='Hello world'
b: (refcount=2, is_ref=0)='Hello world'
$b が $a を参照できるようにし、次のように is_ref refcount を確認します
$a = "こんにちは"
;
$b = &$a;print_r(xdebug_debug_zval('a'));
print_r(xdebug_debug_zval('b'));
?>
a: (refcount=2, is_ref=1)='Hello world'
b: (refcount=2, is_ref=1)='Hello world'
上記のことから、変数が対応する zval コンテナを参照する場合、is_ref は 1 であることが分析できます。
さらに分析して、次のように $b を $a に参照し、$c は $a を指します
<?php $a = "Hello world"; $b = &$a; $c = $a; print_r(xdebug_debug_zval('a')); print_r(xdebug_debug_zval('b')); print_r(xdebug_debug_zval('c')); ?>
印刷結果は以下の通りです
a: (refcount=2, is_ref=1)='Hello world'
b: (refcount=2, is_ref=1)='Hello world'
c: (refcount=1, is_ref=0)='Hello world'
この時点で、php5.5 エンジンが $c の zval コンテナを再構築していることがわかります。コンテナ内のデータ型と値は、$a が指すコンテナ内のデータ型と値とまったく同じです。違いは、refcount と is_ref の値です。
したがって、php5.5 の zval コンテナ内の is_ref 変数は、参照コレクションまたは通常のコレクションのいずれかを識別し、両方が存在する場合、競合の問題を解決するために zval コンテナを複製することがわかります。
概要:
1. php5.5 以降、「変数の割り当て」はポイントの割り当て、つまり変数が特定の zval コンテナを指すことを指します。
2. 「変数参照」は、変数と変数をバインドします。バインドされた変数の 1 つが方向を変えると、相互にバインドされている他の変数の方向も変わります。
変数が変数を再参照すると、元の変数のバインドが解放され、代わりに新しい変数がバインドされます。次のコード:
<?php function foo(&$var) { $var =& $GLOBALS["baz"]; } foo($bar); ?>
これにより、関数の呼び出し時に foo 関数の $var 変数が $bar にバインドされますが、その後 $GLOBALS["baz"] に再バインドされます。関数 foo には変数 $bar が存在しないため ($var として表されますが、$var には変数の内容のみが含まれ、呼び出しはありません)、参照メカニズムを通じて関数呼び出しスコープ内の別の変数に $bar をバインドすることはできません。シンボル テーブルの名前と値のバインディング)。参照リターンを使用して、関数によって選択された変数を参照できます。