イテレータオブジェクトのバグを再現した
PHP5.3.6ではこの問題が発生しなくなっていました。
きのうの http://d.hatena.ne.jp/tanakahisateru/20090827/1251379409 を再現できるコードをのっけときます。
<?php ini_set("display_errors", "1"); error_reporting(E_ALL); header("Content-Type:text/plain"); class MyArrayObject implements IteratorAggregate { private $arr; public function __construct() { $this->arr = func_get_args(); } public function getat($i) { return $this->arr[$i]; } public function len() { return count($this->arr); } public function getIterator() { return new MyArrayObjectIterator($this); } } class MyArrayObjectIterator implements Iterator { private $self; private $position; public function __construct($self) { $this->self = $self; $this->position = 0; } function rewind() { $this->position = 0; } function current() { return $this->self->getat($this->position); } function key() { return $this->position; } function next() { ++$this->position; } function valid() { return $this->position < $this->self->len(); } } function myarray($a,$b,$c){ return new MyArrayObject($a,$b,$c); } echo "test1\n"; $vs = myarray(1,2,3); foreach($vs as $v) { echo $v; // OK: 123 が表示される } echo "\n\n"; echo "test2\n"; foreach(myarray(1,2,3) as $v) { echo $v; // OK: 123 が表示される } echo "\n\n"; echo "test3\n"; $cond = TRUE; $vs = $cond ? myarray(1,2,3) : array(4,5,6); foreach($vs as $v) { echo $v; // OK: 123 が表示される } echo "\n\n"; echo "test4-1 *bug:123 expected\n"; $cond = TRUE; foreach(($cond ? myarray(1,2,3) : array(4,5,6)) as $v) { echo $v; // BUG: ここ通らない } echo "\n\n"; echo "test4-2 *bug:123 expected\n"; $cond = TRUE; $obj = myarray(1,2,3); $obj->p0 = 'foo'; $obj->p1 = 'bar'; foreach(($cond ? $obj : array(4,5,6)) as $v) { echo $v; // BUG: fooとbarが出る } echo "\n\n"; // 構文の第一要素について、式の最上位が演算になっている場合、その評価結果が Traversible であっても、 // 無視して一般のオブジェクトと同じように処理される echo "test5\n"; function a_or_b($cond, $a, $b) { return $cond ? $a : $b; } $cond = TRUE; foreach(a_or_b($cond, myarray(1,2,3), array(4,5,6)) as $v) { echo $v; // OK: 123 が表示される } echo "\n\n"; echo "test6\n"; $vss = array(myarray(1,2,3), array(4, 5, 6)); $cond = TRUE; foreach($vss[intval(!($cond == TRUE))] as $v) { echo $v; // OK: 123 が表示される } echo "\n\n"; // 構文の第一要素が複雑な式であったとしても、最上位が「演算」でなければよい ?>
配列やオブジェクトを出力する演算って、いまのところPHPでは c?a:b の三項演算だけ?でももし、将来オブジェクトに演算したときの振る舞いをユーザ定義できるようになったら…。