<?php
// use ORDER BY belongs_to DESC, id ASC ... or usort() to prepare result set
$resultset = [
['id' => '6a', 'belongs_to' => '5a'],
['id' => '5a', 'belongs_to' => '3a'],
['id' => '8a', 'belongs_to' => '3a'],
['id' => '3a', 'belongs_to' => '1a'],
['id' => '1a', 'belongs_to' => null],
['id' => '2a', 'belongs_to' => null],
['id' => '4a', 'belongs_to' => null],
['id' => '7a', 'belongs_to' => null]
];
foreach ($resultset as $index1 => &$row1) { // make input array modifiable by reference (not working with a copy)
if ($row1['belongs_to']) { // original belongs_to value is not null (not a top-level parent)
foreach ($resultset as $index2 => $row2) { // search for targeted parent
if ($row2['id'] == $row1['belongs_to']) { // parent found
$resultset[$index2]['children'][] = [$row1['id'] => $row1['children'] ?? []]; // store original row as child
unset($resultset[$index1]); // remove original row (no reason to iterate it again in outer loop)
break; // halt inner loop (no reason to iterate further)
}
}
} else { // original belongs_to value is null (top-level parent)
$output[$row1['id']] = $row1['children'] ?? []; // store children to top
}
}
var_export($output);