- 2008年9 月22日(月)
- PHP
shimazakiです。
PHPで配列処理を行うことの出来るforeachですが、不思議な動作に遭遇しました。
// 配列をセット
$arr = array("a","b","c");
// flag初期化
$flag = true;
// foreach処理開始
foreach( $arr as $value ){
//
print("配列の中身:");
var_dump( $arr );
print("<br />n");
if( $flag ){
unset( $arr );
//配列変数を開放
$flag = false;
}
//
print("要素の中身:");
var_dump( $value );
print("<br />n");
}
print("最終的な配列の中身:");
var_dump( $arr );
?>
結果は
配列の中身:array(3) { [0]=> string(1) "a" [1]=> string(1) "b" [2]=> string(1) "c" }
要素の中身:string(1) "a"
配列の中身:NULL
要素の中身:string(1) "b"
配列の中身:NULL
要素の中身:string(1) "c"
最終的な配列の中身:NULL
のように出力されます。
どういうことかというと、foreachはループの都度、配列から値を取り出して代入を行っているものと思っていたのですが、実際にはそうではなく、foreachの処理の開始時点での配列の中身に対して、順次処理を行っている、ということなので、ループの最中に配列の中身を変更してもループ回数や要素が途中で変更されたりはしない、ということです。
不思議だなーと思ってマニュアルを見てみると、ちゃんと書いてありました。
注意: 配列が リファレンス でない限り、foreachは、指定した配列自体に対してではなく、 そのコピーに対して処理を行います。 foreach は配列のポインタに副作用を及ぼします。 foreach の最中やその後で配列のポインタを使用する際は、まずポインタをリセットしてください。
http://jp.php.net/manual/ja/control-structures.foreach.php
(注)下線は追加しました
この手のループ処理は、ブロック内処理が終わるごとにループに関連する処理を行っていると思っていたので、この動作は驚きました。あと、そういうこともちゃんとマニュアルに書いてあることにも驚きました。
ちなみにマニュアルにも書いてある通り参照を使えばループの途中でループ対象の配列の中身を書き換えることも出来ます。
//配列をセット
$arr = array("a","b","c");
//参照用に配列を参照コピー
$refarr = &$arr;
//flag初期化
$flag = true;
//foreach処理開始
foreach( $refarr as $value ){
print("配列の中身:");
var_dump( $refarr );
print("<br />n");
if( $flag ){
$refarr = array();//配列を空にする
$flag = false;
}
print("要素の中身:");
var_dump( $value );
print("<br />n");
}
結果は
配列の中身:array(3) { [0]=> string(1) "a" [1]=> string(1) "b" [2]=> string(1) "c" }
要素の中身:string(1) "a"
最終的な配列の中身:array(0) { }
となります。
1回目のループで配列の中身が空になっているため、ループが1回だけしか処理されません。
ループの中で配列の中身を書き換える人はそんなにいないかもしれませんが、同じループ処理でもforやwhileとは少々異なる処理をしていることは覚えておいて損は無いと思います。
- Newer: PHPの配列結合の違いについてのまとめ
- Older: PHPer向けJavaScript入門
この記事へのコメント: 2件
- 阪口 2008年9 月29日(月) 0:49
-
なんと。
そんな事があったとは。。。。「へぇ」19個くらいです。
JAVAのforeachもいっぺん調べてみますー。 - shimazaki 2008年10 月3日(金) 10:57
-
コメントありがとうございます。
こういうのに遭遇するとPHPって面白い言語だなーと思います。