連想配列にご用心~初期化の有無で結果が変わるよ

 プログラマーならば実務で連想配列を使うことはしょっちゅうだと思います。
今回、現場で連想配列の初期化忘れによる不具合に出会ったので
備忘録兼、同じようなバグで困っている人の手助けになればいいなと思い記事にしました。
記事が長くなるのでご容赦を


下にコードを記述しました。
シリーズごとにキャラクターをグループ化した二次元の
連想配列です。

実際にはDBから取得してくることが多いと思いますがDBから取得したと仮定した
連想配列です。

<?php
$precure["syodai"][0] = 'キュアブラック';
$precure["syodai"][1] = 'キュアホワイト';

$precure["magic"][0] = 'キュアミラクル';
$precure["magic"][1] = 'キュアマジカル';
$precure["magic"][2] = 'キュアフェリーチェ';

$precure["princess"][0] = 'キュアフローラ';
$precure["princess"][1] = 'キュアマーメイド';
$precure["princess"][2] = 'キュアトゥインクル';
$precure["princess"][3] = 'キュアスカーレット';
foreach($precure as $group){
	//$chara = array();//ここで初期化
	foreach ($group as $value) {
		$chara[] = $value;
	}
	$cure[] = $chara;
}
?>

さて、この配列$cureの中身はどのようになるかと言いますと
$charaを初期化しなかった場合のdumpの結果は

array(3) {
  [0]=>
  array(2) {
    [0]=>
    string(21) "キュアブラック"
    [1]=>
    string(21) "キュアホワイト"
  }
  [1]=>
  array(5) {
    [0]=>
    string(21) "キュアブラック"
    [1]=>
    string(21) "キュアホワイト"
    [2]=>
    string(21) "キュアミラクル"
    [3]=>
    string(21) "キュアマジカル"
    [4]=>
    string(27) "キュアフェリーチェ"
  }
  [2]=>
  array(9) {
    [0]=>
    string(21) "キュアブラック"
    [1]=>
    string(21) "キュアホワイト"
    [2]=>
    string(21) "キュアミラクル"
    [3]=>
    string(21) "キュアマジカル"
    [4]=>
    string(27) "キュアフェリーチェ"
    [5]=>
    string(21) "キュアフローラ"
    [6]=>
    string(24) "キュアマーメイド"
    [7]=>
    string(27) "キュアトゥインクル"
    [8]=>
    string(27) "キュアスカーレット"
  }
}

となり、前のループで取得した値を次のループでも格納します。

一方$charaを初期化した場合

array(3) {
  [0]=>
  array(2) {
    [0]=>
    string(21) "キュアブラック"
    [1]=>
    string(21) "キュアホワイト"
  }
  [1]=>
  array(3) {
    [0]=>
    string(21) "キュアミラクル"
    [1]=>
    string(21) "キュアマジカル"
    [2]=>
    string(27) "キュアフェリーチェ"
  }
  [2]=>
  array(4) {
    [0]=>
    string(21) "キュアフローラ"
    [1]=>
    string(24) "キュアマーメイド"
    [2]=>
    string(27) "キュアトゥインクル"
    [3]=>
    string(27) "キュアスカーレット"
  }
}

となりグループごとに格納することが出来ました。

理由は$charaに格納する値は内側のループで取得した値で
その結果が$cure配列に格納されます。

しかしこのとき、$charaに格納された値は消えずに残ったまま2回目のループ処理が
行われるので、2回目のループでは$charaには1回目のループで格納した値と
今回のループで取得した値が格納されることになります。

そのため、ループの回数が増えるたび、格納される値がどんどん積みあがっていきます。

しかし$charaを初期化することで、前のループで取得した値を消すことができます。
よって前のループで取得した値が残らず、次のループで取得した値を$charaに格納できるので
グループごとの配列が取得できるのです。

どっちの結果が正しいかはその時々によって変わるので分かりませんが
初期化をするしないで、求める結果が変わることは確かです。

おしまい。