私は最近、単一のクエリと単一の while ループを使用して、同様のことを行いました。参照を使用して、フラットなデータ構造 (配列) によってツリー データ構造 (配列) を構築します。SPL の必要性は感じなかったので、SPL は関係ありません。より良い配色のGistがGitHubにあります:)
/**
* Each element in the return array has a 'data' key, holding category data,
* like name, and a 'children' key holding its subcategories.
*
* @param resource $resource MySQL resource resulted from mysql_query
* @param string $id_key Name of the 'id' field
* @param string $parent_id_key Name of the 'parent_id' field
* @param boolean $use_cache Use cached result from previous calls. Defaults to TRUE
* @return array
*/
function categories($resource, $id_key, $parent_id_key, $use_cache = true) {
// Cache the categories in a static local variable. This way, the query
// will be executed just for the first function call. Subsequent calls
// will return imediatelly, unless you tell it not to.
static $tree = array();
if ($tree && $use_cache) {
return $tree;
}
// Flat representation of the categories for fast retrieval using array
// keys. Each element will be referenced in the $tree array. This
// allows to build a tree data structure using a flat one.
$flat = array();
// Reset the $tree, in case $use_cache=false in a subsequent call
$tree = array();
while ($row = mysql_fetch_object($resource)) {
$flat[$row->$id_key] = array(
'data' => $row,
'children' => array(),
);
if (array_key_exists($row->$parent_id_key, $flat)) {
// Assign children by reference so that possible subcategories of
// this one will appear in the tree structure ($tree)
$flat[$row->$parent_id_key]['children'][] =& $flat[$row->$id_key];
}
if ($row->$parent_id_key == 0) {
// Assign by reference for synchronizing $flat with $tree;
$tree[] =& $flat[$row->$id_key];
}
}
return $tree;
}
また、関数はデータベースの構造から分離されています。id フィールドを表す文字列と、parent_id フィールドを表す文字列である mysql_query リソースを渡す必要があります。悪い点は、mysql_fetch_object への呼び出しを使用するため、PHP mysql 拡張機能に結合されていることです。おそらく改善される可能性があります。
他のいくつかの利点は、4 番目の (ブール値) パラメータであるキャッシュを無効にするように指示しない限り、後続の呼び出しの結果をキャッシュすることです。
見て、それがあなたに役立つかどうかを確認してください。