Я бы порекомендовал бы Вам литературку для расширения кругозора:
https://www.arbinada.com/node/25
Особое внимание обратить на "Маршрут обхода".
Что касается Вашего вопроса то зависит от того как нужно получить результат - плоско или объемно.
Для простоты, предположим мы хотим получить результат плоским
<?php
/* @var array[] Плоский массив вложенных нод */
$arTree = [];
collectTree( 3, $arTree );
/*
Если сделать var_dump($arTree);
Мы рассчитываем получить следующий массив:
array
{
{
id: 3
title: Cat3
slug: cat3
parent: 0
},
{
id: 6
title: lodki
slug: lodki
parent: 3
},
{
id: 7
title: Samolety
slug: lodki
parent: 6
}
}
*/
function collectTree( $iRootId, $nodeList = [] )
{
/* @var array Массив описывающий ноду $iRootId */
$nodeList[ $iRoot ] = getRootData($iRootId);
/* @var int[] Массив id категорий, который является вложенным по отношению к текущей ноде */
$arRootIncludedNodeId = getSubTreeNodeIds( $iRootId );
if ( !empty( $arRootIncludedNodeId ) )
{
foreach ($arRootIncludedNodeId as $iNode)
{
collectTree( $iNode, $nodeList );
}
}
}
/**
* Возвращает данные по конкретной ноде
* @param int $iRoot
* @return array
*/
function getRootData( $iRoot )
{
// ...
}
/**
* Возвращает ID всех нод, являющихся наследниками $iRoot ноды
* @param int $iRoot
* @return int[]
*/
function getSubTreeNodeIds( $iRoot )
{
// ...
}
?>
Соответственно для объемного нужно немного изменить метод collectTree, чтобы он не дополнял список, а дописывал в нужный элемент