こんな感じの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; }
( ಠ益ಠ)
ステップ実行してみると、
この下の方の$valuenodeを追加しているところで、: // 作った親のノードをルート配列に追加 $tree[] = $typenode; } : // 今の時点で $typenode で親ノードが参照出来るはずで、 // それに対して"values"で引ける子ノード格納用配列に、 // 子のノードを追加 $typenode["values"][] = $valuenode; }
「$typenode」には追加されるものの、
「$treeからたどれる『$typenodeと同じものであるはずのもの』」
には追加されているように見えない。
で、$typenodeそのものがコピーされてしまっているように見える。$tree[] = $typenode;
本当は違っててその後変更が発生しそうになった時にコピーされるんだろうけど。
なのでこうしてみた。=&で参照渡し的な何かになるはずと聞いて。
実行してみた結果。$tree[] =& $typenode;
(╬ಠ益ಠ)
今度は、二週目の
の上の方のところで「新しいノードを作って$typenodeを差し替えた」だけのつもりが、// 親のノードを新規作成し、$typenodeを差し替え $typenode = array("type" => $r["type"], "typeName" => $r["typeName"], "values" => array()); // 親のノードは子を格納する配列を持つ // 作った親のノードをルート配列に追加 $tree[] =& $typenode;
既に一周目でセットした$tree[0]の要素までも差し替わってしまった。
参照渡し…ってそこまで参照なの!?
これ、そもそもマインドモデルが上の図と違ってて、模式図で表せない。
最終的にこうしたら何とかなった。
差し替える前にunsetをする事で、$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; }
$typenodeというシンボルと実体との紐付けが解放されるので、
あらためて作ったarrayをセットしても既存のデータ構造に影響を与えない。
なんだこの仕様。
array関数で新たに配列作って変数に代入する、って
「mallocしてそのポインタを返す」的な感覚かと思ってたら、
「返す先のポインタがあったら指している領域に上書きする」みたいな
日本語すら怪しくなるような動きもするとは。
理解に苦しむ。
0 件のコメント:
コメントを投稿