▼ 2008/01/27(日) 変数管理の基礎(PHPの参照とは何か)-PHP変数管理 (2)
内部構造がわからず、もやもやとした気分でコーディングするのは、あまり気分が良くない。
PHPの変数管理の詳細を知ると、複雑な参照代入や配列などの使い方の幅が増えてくる。はず、ということで、いろいろ調べてみた。変数や関数の受け渡しについては知っているつもりで、間違った知識で書いていることも多いことがわかり、自分でもあぜんとした。ので、いくつかわかった(つもり)のことを書いてみる。
PHP変数管理の目次はこちら
PHPの変数管理の詳細を知ると、複雑な参照代入や配列などの使い方の幅が増えてくる。はず、ということで、いろいろ調べてみた。変数や関数の受け渡しについては知っているつもりで、間違った知識で書いていることも多いことがわかり、自分でもあぜんとした。ので、いくつかわかった(つもり)のことを書いてみる。
PHP変数管理の目次はこちら
■変数管理はワンクッションあり→シンボルテーブル
PHPで、$a='one';と書いた場合、内部的に 変数名a → 値one という単純な表が作られるわけではない。「変数名aは、値の格納庫コンテナ(zval構造体)No.#0001と対応している」というシンボルテーブルが作られ、格納庫(zval)No.#0001にoneという値が書き込まれる。code1
$a='one';
figure1 $a='one'; で作成されるPHP内部の変数管理表
変数名 | 格納庫(zval)No. |
---|---|
a | #0001 |
No. | value | type |
---|---|---|
#0001 | one | string(文字列型) |
参照代入とは -シンボルテーブルの多重割り当て
シンボルテーブルには、同じ格納庫(zval)No.に、複数の変数名が割り当てられることがある。それが参照代入と呼ばれる。
例えば、以下のコードは、同じ格納庫(zval)No.にa,bの変数名が割り当てられる。
code2
$a= <span style="color:red;font-weight:bold;">&</span> $b;
figure2 参照代入された後
変数名 | 格納庫(zval)No. |
---|---|
a | #0001 |
b | #0001 |
No. | 値 | type |
---|---|---|
#0001 | one | string |
code3
$a='one';
$b= & $a;
$b= 'two';
としたとき、同じ格納庫(zval)No.に書き込まれるわけだから、$a,$bともに two となる。ここで実体と呼ばれる、スカラー値が入った格納庫zvalは、決してコピーされていないことに注意する。実体はただ1つ。上の例では、その1つの実体をを呼ぶのに$aとも$bとも使われるわけだ。
C言語のポインタとの違い
ここが、C言語のポインタと違うと言われる理由である。C言語のポインタと同じものでであれば、以下のようになっているはずである。figure3
変数名 | 格納庫(zval)No. |
---|---|
a | #0001 |
b | #0002 |
No. | 値 | type |
---|---|---|
#0001 | one | string |
#0002 | #0001 | (long?) |
この違いを理解しておかないと、後々、いろんなところで、「はまる」ことになる。
$aと$bは等価である。($a =& $b) -ただし、$a,$bがオブジェクトの時は除く
以下のコードは同じ結果となる。$aと$bは等価である。code4
$a='one'; $b= & $a; $a= 'two';と
code5
$a='one'; $b= & $a; $b= 'two';
結果は以下のとおり。
figure4
変数名 | 格納庫(zval)No. |
---|---|
a | #0001 |
b | #0001 |
No. | 値 | type |
---|---|---|
#0001 | two | string |
誤解されがちなのは、=&演算子が、参照「代入」と翻訳されていることから、$b=& $a;としたときに、まるで、$bに何かの値が書き込まれるような感覚になることである。それはCのポインタであり、PHPの参照とは違うことをよく理解する必要がある。あくまでも、PHPの参照代入は、結びつけるべき左辺の変数名をシンボルテーブルに追加することである。シンボルテーブルを利用して、変数名と格納庫(zval)Noを新たに連動させる、ということである。
誤解を恐れずにいえば、$b=& $a;の場合、$bの実体(zval格納庫)はないのだ。もう少し正確にいえば、$aの実体を間借りするようなものだ。この間借りすることをもって、エイリアスという言い方をする人がいるようだ。もっと正確にいえば、$aと$bは等価なので、$aの実体を$bの実体としても扱う、ということになる。
ただし、上記は、オブジェクトの時だけは異なった結論になる。それは、のちほど説明したい。
unset と =null の違い
では、ここでunset($a)としたら、どうなるか。$a=null;とどう違うか、検証する。
まず、$a=nullであれば、格納庫(zval)No.#0001にnull値が書き込まれるわけだから、$a,$bともにnullとなる。$a,$bは連動しているのだ。
ではunsetはどうだろうか。
code6
unset($a);unsetは、「変数を破棄する」でない。「シンボルテーブルからその変数名を削除する」という動作をする。つまり、
figure5
変数名 | 格納庫(zval)No. |
---|---|
b | #0001 |
No. | 値 | type |
---|---|---|
#0001 | two | string |
となるので、$aはなくなってしまうが、$bの値はtwoのままである。
つまり
code7
$a='one'; $b= & $a; $a= 'two'; unset ($a);とすると、$bの値は、 two となる。
Ohhh!まるで、$bが$aをヤドカリのように乗っ取ってしまったようだ。
まとめ
このようにPHPでは、変数の名前とその値は切り離されており、シンボルテーブルがそれを結びつける働きをしている。シンボルテーブルでは、複数の変数名に対して、同じ実際の値(実体:zval構造体に収納)を、対応(reference or asign)させるさせることができるため、柔軟な変数運用をすることができる。figure6
変数名($a) | →シンボルテーブル | →実際の値(実体:zval構造体に収納) |
変数名($b) | ||
変数名(・・・) |
次回は、$a=$b;について説明したい。単純であるが、奥が深いcodeである。
PHP変数管理の目次はこちら
- TB-URL http://www.cpa-lab.com/tech/029/tb/
-
▼
変数の代入は、値のコピーにあらず
CPA-LABテクニカル 前回の変数管理の基礎(PHPの参照とは何か) でシンボルテーブルについて説明した。これがわかっていないとPHPの変数管理はわからない。今回は、もっとも基本的な変数の値の代入、について説明する。code1$a=$bなぜ、こんな単純なことをいちいち説明しなけれ...
1: FCC 2011年11月28日(月) 午前10時27分
おー。それしらんかっとんてんちんとんしゃん