Referencje, z zaletami, których kolejność nie ma znaczenia (węzły podrzędne mogą pojawić się przed ich węzłami nadrzędnymi):
$tree = array('NULL' => array('children' => array()));
foreach($array as $item){
if(isset($tree[$item['id']])){
$tree[$item['id']] = array_merge($tree[$item['id']],$item);
} else {
$tree[$item['id']] = $item;
}
$parentid = is_null($item['id_parent']) ? 'NULL' : $item['id_parent'];
if(!isset($tree[$parentid])) $tree[$parentid] = array('children' => array());
//this & is where the magic happens: any alteration to $tree[$item['id']
// will reflect in the item $tree[$parentid]['children'] as they are the same
// variable. For instance, adding a child to $tree[$item['id']]['children]
// will be seen in
// $tree[$parentid]['children'][<whatever index $item['id'] has>]['children]
$tree[$parentid]['children'][] = &$tree[$item['id']];
}
$result = $tree['NULL']['children'];
//always unset references
unset($tree);