こんな感じのDBから読んできたデータから、
こんな構造を作りたいなと思ったのです。
こんな感じかな。
<?php
//ここから
function row($type,$typeName,$value1,$value2){
return array("type" => $type,
"typeName" => $typeName,
"value1" => $value1,
"value2" => $value2);
}
$rows = array(row(1,"あ","ABC","DEF"),
row(1,"あ","AAA","BBB"),
row(1,"あ","XXX","YYY"),
row(2,"い","BEEF","PORK"),
row(2,"い","COFFEE","TEA"),
row(2,"い","MILK","COCOA"));
//ここまではサンプルデータを作っているところなので本題とは関係なし。
//データはソートはされているものとする。
$tree = array(); // $treeが最終的なルート配列オブジェクト
$prevType = null; // Typeが変わったらこの処理をする…というためのもの
foreach($rows as $r){ //1行ずつ読む
if($prevType !== $r["type"]){ //もしTypeが変わったら
// 変更チェック用の変数を更新し
$prevType = $r["type"];
// 親のノードを新規作成し、$typenodeを差し替え
$typenode = array("type" => $r["type"],
"typeName" => $r["typeName"],
"values" => array()); // 親のノードは子を格納する配列を持つ
// 作った親のノードをルート配列に追加
$tree[] = $typenode;
}
// 子のノードを作成
$valuenode = array("value1" => $r["value1"],
"value2" => $r["value2"]);
// 今の時点で $typenode で親ノードが参照出来るはずで、
// それに対して"values"で引ける子ノード格納用配列に、
// 子のノードを追加
$typenode["values"][] = $valuenode;
}
実行してみた結果。( ಠ益ಠ)
ステップ実行してみると、
:
// 作った親のノードをルート配列に追加
$tree[] = $typenode;
}
:
// 今の時点で $typenode で親ノードが参照出来るはずで、
// それに対して"values"で引ける子ノード格納用配列に、
// 子のノードを追加
$typenode["values"][] = $valuenode;
}
この下の方の$valuenodeを追加しているところで、「$typenode」には追加されるものの、
「$treeからたどれる『$typenodeと同じものであるはずのもの』」
には追加されているように見えない。
で、$typenodeそのものがコピーされてしまっているように見える。$tree[] = $typenode;
本当は違っててその後変更が発生しそうになった時にコピーされるんだろうけど。
なのでこうしてみた。=&で参照渡し的な何かになるはずと聞いて。
実行してみた結果。$tree[] =& $typenode;
(╬ಠ益ಠ)
今度は、二週目の
// 親のノードを新規作成し、$typenodeを差し替え
$typenode = array("type" => $r["type"],
"typeName" => $r["typeName"],
"values" => array()); // 親のノードは子を格納する配列を持つ
// 作った親のノードをルート配列に追加
$tree[] =& $typenode;
の上の方のところで「新しいノードを作って$typenodeを差し替えた」だけのつもりが、既に一周目でセットした$tree[0]の要素までも差し替わってしまった。
参照渡し…ってそこまで参照なの!?
これ、そもそもマインドモデルが上の図と違ってて、模式図で表せない。
最終的にこうしたら何とかなった。
$tree = array();
$prevType = null;
foreach($rows as $r){
if($prevType !== $r["type"]){
$prevType = $r["type"];
unset($typenode);
$typenode = array("type" => $r["type"],
"typeName" => $r["typeName"],
"values" => array());
$tree[] =& $typenode;
}
$valuenode = array("value1" => $r["value1"],
"value2" => $r["value2"]);
$typenode["values"][] = $valuenode;
}
差し替える前にunsetをする事で、$typenodeというシンボルと実体との紐付けが解放されるので、
あらためて作ったarrayをセットしても既存のデータ構造に影響を与えない。
なんだこの仕様。
array関数で新たに配列作って変数に代入する、って
「mallocしてそのポインタを返す」的な感覚かと思ってたら、
「返す先のポインタがあったら指している領域に上書きする」みたいな
日本語すら怪しくなるような動きもするとは。
理解に苦しむ。



