free as in air

2007|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|09|11|12|
2012|03|04|05|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|03|04|06|09|
トップ «前の日記(2013-02-27) 最新 次の日記(2013-03-14)» /編集

2013-03-10 [長年日記]

§ [php] Re: PHPとかいう糞言語

先にまとめ。

  1. 既にbravewoodさんが、PHPは代入と参照の違いPHPの代入と参照の違い2を書いていたし、そちらのほうが詳しいですorz。
  2. PHPのリファレンス!=Cのポインタ
  3. 実は、PHPの変数はすべて値に対するリファレンスらしいですよ、どうやら。
  4. 元記事の普通の変数で確かめてる部分はたぶん勘違い。var_dump()は値渡しの関数なので、普通の変数を引数にして呼び出してもリファレンスとして表示されるわけがない。
  5. しかし、リファレンス作った時に、右辺にもリファレンスを示すフラグがつくらしい。GC用のリファレンスカウントのためかもしれんが。
  6. 配列の要素のリファレンスは仕様。(配列内のリファレンスの挙動はその要素ごとに決まる)

実体はこの辺か。

  • zend_vm_def.h:ZEND_VM_HANDLER(39, ZEND_ASSIGN_REF, VAR|CV, VAR|CV)
  • zend_execute.c:static void zend_assign_to_variable_reference(zval **variable_ptr_ptr, zval **value_ptr_ptr TSRMLS_DC)

変数のアドレスとるだけと思いきやだいぶ処理してるし、全然意味わからん…。

ところで、PHPリファレンス:リファレンス解除(ややこしい)を読むと何か変な気がしてきたので、元記事コードを改変してみる。

/cygdrive/c/xampp/php/php.exe -r '$v = 1;$ref = &$v;var_dump( $ref );'
int(1)

Oh...

困ったときはマニュアルを参照。var_dumpの定義。PHPリファレンスにあるリファレンス渡しではない。値渡し(デフォルト)で呼び出すので&string("b")とかそんな表示には、なりゃしやんせん。

いやほんと、PHPは糞みんなもっとマニュアルと本体コード読んだらいいと思うよ。

配列の要素のリファレンスは仕様(配列内のリファレンスの挙動はその要素ごとに決まる)だそう。PHP 5 以降では、配列を参照渡しすることでその値を直接変更できるようになりましたの例で、値の要素の参照を取得したあとはunsetしろって書いてあるから、そういう使い方を想定してるんじゃないですかね。

/cygdrive/c/xampp/php/php.exe -r '$array = array(1,2,3);$ref = &$array[1];unset($ref);var_dump($array);'
array(3) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  int(3)
}

しかし逆もありなのね。これは動作として違和感ないけど、何に使うのだろうか。

/cygdrive/c/xampp/php/php.exe -r '$array = array(1,2,3);$x="aaa";$array[1] = &$x;var_dump($array);'
array(3) {
  [0]=>
  int(1)
  [1]=>
  &string(3) "aaa"
  [2]=>
  int(3)
}