Certainly the first piece of advice that I have is, you should avoid performing recursive/iterated calls to your database. You should make a single call to extract all of the desired rows in a single result set and let php do the hard part.
I've decided to try a non-recursive approach. To permit this, the result set must be prepared so that "grander" children are listed first. Now, I realize that it is entirely possible that your sample data doesn't actually represent your project values and sorting cannot be used to prepare the result set adequately -- you'll have to let me know (and perhaps update your question with more accurate sample data).
[see inline comments for what's happening in my script]
*If you aren't using php7+, then my null coalescing operator ($row1['children'] ?? []
) will cause issues.
You can use: (isset($row1['children']) ? $row1['children'] : []
Code: (Demo)
// 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);
Output:
array (
'1a' =>
array (
0 =>
array (
'3a' =>
array (
0 =>
array (
'5a' =>
array (
0 =>
array (
'6a' =>
array (
),
),
),
),
1 =>
array (
'8a' =>
array (
),
),
),
),
),
'2a' =>
array (
),
'4a' =>
array (
),
'7a' =>
array (
),
)