Duas técnicas para implementar classificação hierárquica infinita em PHP

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.

Tags: PHP classificação hierárquica recursão referências estrutura de dados

Publicado em 6-20 17:56