Thought I'd toss something of the sort off.
function build_tree($root_id=0)
{ $sql = "select id,parentid,blah from mytable";
$result = mysql_query($sql);
// And that's one of the biggest timesinks out of the way.
$tree = array();
// Each row in the table gets a row in the tree array.
// Each row in the tree has two elements:
// $tree[$id]['blah'] is the blah field from table row $id
// $tree[$id]['children'] are the children of table row $id
//
while($row=mysql_fetch_array($result))
{ $id = $row['id'];
$parentid = $row['parentid'];
$blah = $row['blah'];
$tree[$id]=array('children'=>array(), 'blah'=>$blah);
if($id!=$root_id)
$tree[$parentid]['children'][]=$id; //I'm home, Mum!
}
// On the off-chance that we pulled too many rows
// (since we probably couldn't tell in advance which rows are below
// the root until we'd read the entire table) we kill any
// rows that aren't accessible from the root here.
// The following block of code isn't necessary if it is known
// that the entire table is part of the tree. With suitable assignment
// of ids to rows, this part may be avoided, by allowing the construction
// of a suitable WHERE clause in the above query.
//
// In fact, this step isn't necessary except for memory savings anyway.
// If those savings aren't significant compared with the additional
// time needed to run it, then don't bother.
//
// If there is a cycle in the tree's structure (i.e., it isn't a tree
// after all), then this loop will be infinite.
$temptree=array($root_id=>$tree[$root_id]);
$found_ids=array($root_id);
do
{ $row=$temptree[array_pop($found_ids)];
foreach($row['children'] as $child) $temptree[$child]=$tree[$child];
$found_ids=array_merge($found_ids,$children);
} while(count($found_ids));
$tree=$temptree;
// Return that tree
return $tree;
}
So by applying that bit of forethought, that show_branch() function of Drakla's becomes
function show_branch($tree, $catid=0)
{ static $depth=-1;
$depth++;
$padder=str_repeat($depth,"\t");
$name="<a href='browse-cats.php?catid=".$catid."'>".$tree[$catid]['blah']."</a>";
echo $padder.$name.'<br>';
foreach($tree[$catid]['children'] as $child)
show_branch($tree, $child);
$depth--;
}
Note that that's off the cuff; may have a couple of rough edges. Needless to say, "blah" is short for whatever other fields (besides id and parentid) are being returned.
If the tree structure doesn't change much then after it's generated once, it could be cached in some way and restored from that as necesssary. (var_export($tree), for example will generate a PHP-readable representation of $tree as a bunch of array() declarations that can be stored and retrieved as needed.)