reset()を伴わないwhile each()ループはforeachに書き換える - PHP救命病棟

reset()を伴わないwhile each()ループはforeachに書き換える - PHP救命病棟

 先日ハマっていた人がいたのでメモ。

 僕は通常、

foreach ($array as $key => $val) {
    ...
}

のように書いているのですが、これを

while (list($key, $val) = each($array)) {
    ...
}

のように書く人もいます。

 昔のPHPはforeachがなかったような気がするので、たぶん古くからPHPで書いているのでしょう*1

 ところで上のようにeach()を使ってループをする場合は直前にreset($array)を書いておくべきです*2

 function内の変数であればそのスコープで使っている限り想定通りに動くかもしれませんが*3、これがグローバル変数だったりするとeach()の戻り値がどこから始まるのか分からず*4ひどい目に合う可能性があります*5

 each()単独で使っている場合はともかく、上記のようにwhileループでeach()を使っている場合は十中八九foreachで書き直しても大丈夫なので、可能な限り修正しておいたほうがよいでしょう*6

 特にグローバル変数*7を使っているときは書き換えたほうが安全です。メンテナンスをしてプログラムを書き換えた時に、ほかの場所でそのグローバル変数の配列ポインタが変更されてるかもしれませんからね。

 ちなみに、類似のケースにresetを伴わないwhile next()ループってのもあります*8

 この場合は

foreach ($array as $val) {
    ...
}

とすればよいでしょう。

*1Perlの人かもしれないけど、でも、Perlの人はforeachを使うよね?

*2:もちろん配列ポインタが移動していてほしいときは必要じゃないです。

*3:引数で渡されたarrayがどう振る舞うのかは知らないけど、PHPに思い入れはないので調べたりはしない。

*4:例えば、他のどこかで同じようなループをしていれば全くループがまわらないことになる。

*5:というか、その人はそれでハマっていた。

*6:単にreset()を書き足すのもありだけど、僕ならまぎれのないようにforeachにする。

*7:$_で始まるスーパーグローバル変数とか。

*8:その人はnext()を知らないのか、$keyを必要としない場合でもeach()を使っていましたが。