foreach()だと参照を要素に設定した配列の要素が上手く取れなくて、for()に戻した。
題名が意味不明です。スクリプトを見て頂いた方が速い。
test015.php:
<?php class Klass1 { var $_v; function Klass1($v) { $this->_v = $v; } } class Klass2 { var $_v; function Klass2($v) { $this->_v = $v; } } class Klass3 { var $_els; function Klass3() { $this->_els = array(); } function add(&$e) { $this->_els[] =& $e; } function dump() { for ($i = 0; $i < count($this->_els); $i++) { printf("class : %s, value = %s\n", get_class($this->_els[$i]), $this->_els[$i]->_v); } } } $elements = array(); for ($i = 0; $i < 4; $i++) { // (1) switch ($i % 2) { case 1: $elements[] =& new Klass2("Hello2, [{$i}]"); break; case 0: $elements[] =& new Klass1("Hello1, [{$i}]"); break; } } $k =& new Klass3(); // (2) foreach ($elements as $e) { $k->add($e); } $k->dump();
(1)のループが終わると、ぱっと見には$elementsには Klass1, Klass2, Klass1, Klass2 の順で入っていると思うはずです。
ところが、実行してみると・・・
(PHP4.4.7 on WinXPSP2)
DOS> php test015.php class : klass2, value = Hello2, [3] class : klass2, value = Hello2, [3] class : klass2, value = Hello2, [3] class : klass2, value = Hello2, [3]
(PHP5.2.4でも同じ)
変ですよね。add()の引数の参照渡しの書き方もおかしくないはずです。
ぱっと見、状況としては一番最後に配列に追加した要素で全部上塗りされているように見えます。
数時間ほど嵌ったのですが、「もしやforeach()のループでzvalの参照が崩れてしまうのでは・・・」と思い立ち、試しにfor()文で(2)のループを書き直してみたら・・・あら不思議。
test016.php:
<?php // ... (test015.phpと同じ) $k =& new Klass3(); // (2): test015.phpのforeach()をfor()に置き換えてみる for ($i = 0; $i < count($elements); $i++) { $k->add($elements[$i]); } $k->dump();
DOS> php test016.php class : klass1, value = Hello1, [0] class : klass2, value = Hello2, [1] class : klass1, value = Hello1, [2] class : klass2, value = Hello2, [3]
という次第でした。
で、例によりこれもKinoWikiのWikiパーサをYakiBikiに移植=PHP4対応に書き直し中に発生した現象。
KinoWikiのWikiパーサはPHP5前提に書かれているので、一つ前のeval()とcall_user_func()の参照返し関数絡みもそうだが、基本オブジェクトのインスタンスzvalへの参照でのバッドノウハウが殆ど考えなくて良くなっている。
それを、バッドノウハウ満載のPHP4に対応させるのだから、この程度の嵌り洗礼は前提と考えるべきか・・・!
というかシビアな話、YakiBikiがまともに動き出す頃にはPHP4のホスティングサービスなんて無くなってるんじゃねぇ?よほど古いところとか・・・。
ああ。_| ̄|○ 鬱だ...