PHP言語エンジンのif文の数は世界一ぃ〜〜〜
PHP5.3.6ではこの問題が発生しなくなっていました。
PHP5.2.6なんだけど。
イテレータでまわせるオブジェクトを書けるので、まわしてみた。
<?php class MyArrayObject implements IteratorAggregate { // ... 配列みたいなオブジェクトを実装 public function getIterator() { return new MyArrayObjectIterator($this); } } class MyArrayObjectIterator implements Iterator { // ... イテレータの実装 } function myarray($a,$b,$c){ return new MyArrayObject($a,$b,$c); } ?>
というようなオブジェクトと関数があるとして、以下のようにやりたい。
<?php $vs = myarray(1,2,3); foreach($vs as $v) { echo $v; // OK: 123 が表示される } ?>
まあ仕様どおり。じゃあ変数を省略する。
<?php foreach(myarray(1,2,3) as $v) { echo $v; // OK: 123 が表示される } ?>
OK。そろそろ実用で、本物Arrayと偽Arrayの相互運用。
<?php $cond = TRUE; $vs = $cond ? myarray(1,2,3) : array(4,5,6); foreach($vs as $v) { echo $v; // OK: 123 が表示される } ?>
これもOK。さてそれじゃ、上の二つを組み合わせて…
<?php $cond = TRUE; foreach(($cond ? myarray(1,2,3) : array(4,5,6)) as $v) { echo $v; // BUG: ここ通らない } ?>
なんじゃこりゃ、動かん。なぜに?! 個々に単体で使うとOKで、組み合わせるとバグるって、そんなの、プログラム言語じゃねーよ。(ちなみに、$cond=FALSE なら echo のとこ通るのよね。)
似たようなこと書いても、別の理由で偶然動くかもしれないから、完全な再現性があるのかわからないけど、少なくとも、特定のシチュエーションで起こったのは確かで、それも、2回も遭遇した。
なんか、PHPってもしかしてこんな実装?
foreach構文の第一要素について...
- 変数の場合:変数がarrayか->Traversableか->他のオブジェクトか->X
- 関数コールの場合:戻り値がarrayか->Traversableか->他のオブジェクトか->X
- 式の場合:式の結果値かarrayか->オブジェクトか->X (PHP5開発時の実装漏れ)
ふつうの言語なら、こう↓だよね。
- 式(単変数や関数コールも含む)を評価して値を得る。
- 値に対して反復インターフェース(C言語で仕様概念上のね)を要求する。※反復できない値はゼロ回反復するインターフェースを提供する。
- 反復インターフェースを使用。
こんな感じのマトモな言語じゃないと、リファクタリング結果が等価になるって保障できないよなぁ…。つくづく、PHP5のときやるべきだったのは、インターフェースじゃなくて、配列や構文解析など、従来の言語コアへのてこ入れだったと思う。