A Nova Classe Dom\HTMLDocument no PHP 8.4

Como o PHP 8.4 introduz um parser HTML5 completo baseado no motor Lexbor, com suporte nativo a querySelector() e querySelectorAll(), resolvendo as limitações do DOMDocument clássico com marcação moderna.

Por mais de 15 anos, a única forma de manipular HTML no PHP foi a classe DOMDocument, construída sobre o libxml2 — uma biblioteca que entende apenas HTML 4.01. Na prática, isso significa que marcações modernas, tags não fechadas e comportamentos de parsing que qualquer navegador trata normalmente acabavam gerando warnings, elementos deslocados ou simplesmente documentos quebrados. O PHP 8.4 introduziu a classe Dom\HTMLDocument, um parser HTML5 completo baseado no motor Lexbor, que segue o WHATWG HTML Living Standard — a mesma especificação que os navegadores implementam.

O problema com DOMDocument

Carregar HTML5 com a classe antiga sempre exigia suprimir warnings e ainda corria o risco de reordenar ou descartar elementos que o libxml2 não reconhecia:

$dom = new DOMDocument();
libxml_use_internal_errors(true); // precisa suprimir warnings manualmente
$dom->loadHTML('<article><p>Texto</p></article>');
// tags HTML5 como <article>, <section> e atributos modernos
// nem sempre são interpretados do jeito que o navegador interpretaria

Criando um documento com Dom\HTMLDocument

A nova classe não tem construtor público — os documentos são criados por métodos estáticos nomeados: createFromString(), createFromFile() e createEmpty(). Por padrão, ela já espera UTF-8 e não exige suprimir erros para HTML malformado, porque o parser resolve isso do mesmo jeito que um navegador resolveria:

use Dom\HTMLDocument;

$html = <<<'HTML'
<!doctype html>
<html>
<body>
    <article class="post">
        <h2>Título do post</h2>
        <p>Primeiro parágrafo.</p>
    </article>
</body>
</html>
HTML;

$dom = HTMLDocument::createFromString($html);
echo $dom->saveHtml();

Seletores CSS nativos: querySelector e querySelectorAll

Essa é a mudança mais sentida no dia a dia: não é mais preciso montar expressões XPath só para buscar um elemento. querySelector() devolve o primeiro elemento que casa com o seletor (ou null, se nenhum casar), e querySelectorAll() devolve todos os elementos que casam, na ordem do documento:

$dom = Dom\HTMLDocument::createFromString($html);

$titulo = $dom->querySelector('article.post > h2');
echo $titulo?->textContent; // Título do post

foreach ($dom->querySelectorAll('article p') as $paragrafo) {
    echo $paragrafo->textContent . PHP_EOL;
}

Chamar querySelector() a partir de um elemento (em vez do documento) limita a busca aos descendentes daquele elemento, o que é útil para escopar a busca dentro de um bloco específico já encontrado antes.

Lendo HTML de uma página real

Um uso comum é extrair dados de uma página baixada de outro lugar, algo que antes exigia muita cautela com o parser antigo:

$dom = Dom\HTMLDocument::createFromString($htmlDaPagina);

$links = [];
foreach ($dom->querySelectorAll('nav a') as $link) {
    $links[] = [
        'texto' => trim($link->textContent),
        'href' => $link->getAttribute('href'),
    ];
}

Quando usar

Cuidados

Dom\HTMLDocument é uma classe nova, separada de DOMDocument — não é uma troca de comportamento na classe antiga, então código existente continua funcionando exatamente como antes. As duas classes não são intercambiáveis: um objeto Dom\HTMLDocument não pode ser passado para uma função que espera um DOMDocument clássico. Além disso, assim como no navegador, HTML malformado é corrigido silenciosamente (tags implícitas de <html>, <head> e <body> podem ser inseridas automaticamente), o que é exatamente o comportamento esperado, mas pode surpreender quem espera um retorno fiel byte a byte do que foi passado.

Compatibilidade

Dom\HTMLDocument foi introduzida no PHP 8.4 (lançado em novembro de 2024) e exige essa versão ou superior — não há como usá-la em versões anteriores, já que depende do novo motor de parsing Lexbor incluído na extensão DOM a partir dessa release.

documentação oficial

Conclusão

Dom\HTMLDocument traz o PHP para o mesmo padrão de interpretação de HTML que os navegadores já usam há anos, eliminando as gambiarras que cercavam o DOMDocument clássico ao lidar com marcação moderna. Combinada com querySelector() e querySelectorAll(), ela torna scraping, parsing de templates e manipulação de HTML no servidor muito mais parecidos com o que já é familiar do JavaScript no navegador.

Tecnologia:
php

Deixe seu Comentário!

Dúvida, sugestão ou só um "valeu!" — tudo é bem-vindo por aqui.

Comentário
Nome
Email
lock Seu e-mail não será publicado.