Em cenários onde se necessita organizar dados em estruturas hierárquicas com múltiplos níveis, como categorias de menus ou departamentos de uma organização, o armazenamento no banco de dados comum inclui um campo de ID pai para indicar a relação de pertencimento. Para exibir esses dados com a devida profundidade, é preciso processar a lista achatada recuperada do banco, o que pode ser feito de duas formas principais: recursivamente ou através de uma abordagem com referências.
Método Recursivo: Lógica Convencional
Partindo de um array bidimensional obtido do banco de dados, a lógica recursiva percorre a coleção, buscando elementos cujo identificador de pai corresponda ao identificador atual, e repete o processo até não haver mais correspondências. O código a seguir ilustra uma implementação disso, onde a função retorna um array linear ordenado, incluindo um campo de nível para auxiliar na exibição com recuo visual.
function construirHierarquiaRecursiva($dados, $idPai = 0, $nivel = 0) {
$listaOrdenada = [];
foreach ($dados as $chave => $registro) {
if ($registro['id_categoria_pai'] == $idPai) {
$registro['nivel'] = $nivel;
$listaOrdenada[] = $registro;
unset($dados[$chave]);
$listaOrdenada = array_merge($listaOrdenada, construirHierarquiaRecursiva($dados, $registro['id_categoria'], $nivel + 1));
}
}
return $listaOrdenada;
}
Otimização via Referências: Evitando Recursão
Embora intuitivo, o método recursivo pode consumir muitos recursos e ter desempenho inferior em grandes volumes de dados. Uma alternativa mais eficiente utiliza referências para construir a estrutura em uma única iteração, organizando os elementos em uma árvore aninhada. Primeiro, reindexa-se o array original usando o identificador único como chave.
function gerarArvorePorReferencia($dados) {
$tabelaAuxiliar = [];
foreach ($dados as $item) {
$tabelaAuxiliar[$item['id_categoria']] = $item;
}
$arvore = [];
foreach ($tabelaAuxiliar as $id => $elemento) {
$idPai = $elemento['id_categoria_pai'];
if (isset($tabelaAuxiliar[$idPai])) {
$tabelaAuxiliar[$idPai]['subcategorias'][] = &$tabelaAuxiliar[$id];
} else {
$arvore[] = &$tabelaAuxiliar[$id];
}
}
return $arvore;
}
Explicando a segunda etapa: ao iterar sobre a tabela auxiliar, para cada elemento, verifica-se se o seu pai existe na tabela. Se existir, adiciona-se uma referência do elemento atual à chave "subcategorias" do pai. Caso contrário, ele é considerado um nó raiz e adicionado ao array resultante. O uso de referências é crucial, pois permite que alterações subsequentes na estrutura (como a adição de filhos) sejam refletidas corretamente.
Considere um conjunto de dados exemplo:
[
['id_categoria' => 100, 'nome' => 'Painel Principal', 'id_categoria_pai' => 0],
['id_categoria' => 116, 'nome' => 'Administração', 'id_categoria_pai' => 0],
['id_categoria' => 120, 'nome' => 'Lista de Administradores', 'id_categoria_pai' => 116],
['id_categoria' => 121, 'nome' => 'Adicionar Administrador', 'id_categoria_pai' => 116],
['id_categoria' => 122, 'nome' => 'Visão Geral de Dados', 'id_categoria_pai' => 100],
['id_categoria' => 123, 'nome' => 'Registro de Atualizações', 'id_categoria_pai' => 100],
]
Ao aplicar a função gerarArvorePorReferencia, obtém-se uma estrutura hierárquica com dois elementos raiz, cada um conetndo um array "subcategorias" com seus respectivos filhos. Esta estrutura é ideal para serialização em JSON para consumo em frontend ou para posterior conversão em uma lista linear, se necessário. A abordagem com referências oferece complexidade temporal linear, sendo significativamente mais rápida que a recursão para grandes conjuntos de dados.