You'll want to minimize the number of passes you do, by doing a recursive function you are potentially setting yourself up for a serious problem of performance later. By doing a single pass and uses references you can have this run real fast and work very nicely. The memory usage will also be slightly higher than the original dataset since everything is done by reference and not by copy. If you update one of the records then all the records update with it.
input array
$rows = [
[ 'id' => 1, 'parent' => null ],
[ 'id' => 2, 'parent' => 1 ],
[ 'id' => 3, 'parent' => 1 ],
[ 'id' => 4, 'parent' => 2 ],
[ 'id' => 5, 'parent' => 3 ],
[ 'id' => 6, 'parent' => 4 ],
[ 'id' => 7, 'parent' => 5 ],
[ 'id' => 8, 'parent' => 6 ],
[ 'id' => 9, 'parent' => 7 ],
[ 'id' => 10, 'parent' => 8 ],
];
variable where you'll store your references
$tree = [];
loop the record set
foreach($rows as $row) {
checking here to see if you've added this row, in theory this should always come back true unless you have duplicate entries
if (
false === array_key_exists($row['id'], $tree) ||
false === array_key_exists('data', $tree[$row['id']])
) {
$tree[$row['id']]['data'] = $row;
}
checking to see if you have a parent, and then if the parent has been added yet and/or if it's children has been initialized
if (
$row['parent'] &&
(
false === array_key_exists($row['parent'], $tree) ||
false === array_key_exists('children', $tree[$row['parent']])
)
) {
$tree[$row['parent']]['children'] = [];
}
add a reference of the child onto the parent, take extra care to note the & which says it's by reference
if ($row['parent']) {
$tree[$row['parent']]['children'][] = &$tree[$row['id']];
}
}
$tree becomes the following
[
1 =>
[
'data' =>
[
'id' => 1,
'parent' => NULL,
],
'children' =>
[
0 =>
[
'data' =>
[
'id' => 2,
'parent' => 1,
],
'children' =>
[
0 =>
[
'data' =>
[
'id' => 4,
'parent' => 2,
],
'children' =>
[
0 =>
[
'data' =>
[
'id' => 6,
'parent' => 4,
],
'children' =>
[
0 =>
[
'data' =>
[
'id' => 8,
'parent' => 6,
],
'children' =>
[
0 =>
[
'data' =>
[
'id' => 10,
'parent' => 8,
],
],
],
],
],
],
],
],
],
],
1 =>
[
'data' =>
[
'id' => 3,
'parent' => 1,
],
'children' =>
[
0 =>
[
'data' =>
[
'id' => 5,
'parent' => 3,
],
'children' =>
[
0 =>
[
'data' =>
[
'id' => 7,
'parent' => 5,
],
'children' =>
[
0 =>
[
'data' =>
[
'id' => 9,
'parent' => 7,
],
],
],
],
],
],
],
'name' => 'test',
],
],
],
2 =>
[
'data' =>
[
'id' => 2,
'parent' => 1,
],
'children' =>
[
0 =>
[
'data' =>
[
'id' => 4,
'parent' => 2,
],
'children' =>
[
0 =>
[
'data' =>
[
'id' => 6,
'parent' => 4,
],
'children' =>
[
0 =>
[
'data' =>
[
'id' => 8,
'parent' => 6,
],
'children' =>
[
0 =>
[
'data' =>
[
'id' => 10,
'parent' => 8,
],
],
],
],
],
],
],
],
],
],
3 =>
[
'data' =>
[
'id' => 3,
'parent' => 1,
],
'children' =>
[
0 =>
[
'data' =>
[
'id' => 5,
'parent' => 3,
],
'children' =>
[
0 =>
[
'data' =>
[
'id' => 7,
'parent' => 5,
],
'children' =>
[
0 =>
[
'data' =>
[
'id' => 9,
'parent' => 7,
],
],
],
],
],
],
],
'name' => 'test',
],
4 =>
[
'data' =>
[
'id' => 4,
'parent' => 2,
],
'children' =>
[
0 =>
[
'data' =>
[
'id' => 6,
'parent' => 4,
],
'children' =>
[
0 =>
[
'data' =>
[
'id' => 8,
'parent' => 6,
],
'children' =>
[
0 =>
[
'data' =>
[
'id' => 10,
'parent' => 8,
],
],
],
],
],
],
],
],
5 =>
[
'data' =>
[
'id' => 5,
'parent' => 3,
],
'children' =>
[
0 =>
[
'data' =>
[
'id' => 7,
'parent' => 5,
],
'children' =>
[
0 =>
[
'data' =>
[
'id' => 9,
'parent' => 7,
],
],
],
],
],
],
6 =>
[
'data' =>
[
'id' => 6,
'parent' => 4,
],
'children' =>
[
0 =>
[
'data' =>
[
'id' => 8,
'parent' => 6,
],
'children' =>
[
0 =>
[
'data' =>
[
'id' => 10,
'parent' => 8,
],
],
],
],
],
],
7 =>
[
'data' =>
[
'id' => 7,
'parent' => 5,
],
'children' =>
[
0 =>
[
'data' =>
[
'id' => 9,
'parent' => 7,
],
],
],
],
8 =>
[
'data' =>
[
'id' => 8,
'parent' => 6,
],
'children' =>
[
0 =>
[
'data' =>
[
'id' => 10,
'parent' => 8,
],
],
],
],
9 =>
[
'data' =>
[
'id' => 9,
'parent' => 7,
],
],
10 =>
[
'data' =>
[
'id' => 10,
'parent' => 8,
],
],
]