xml_set_end_namespace_decl_handler()
A função xml_set_end_namespace_decl_handler() do PHP registra um callback para o fim de declarações de namespace no parser XML SAX.
A função xml_set_end_namespace_decl_handler() é uma função nativa do PHP que registra um callback definido pelo usuário para ser executado sempre que o parser XML SAX atingir o fim de um elemento que declarou um ou mais namespaces XML. Ela é a contraparte de fechamento de xml_set_start_namespace_decl_handler(): o handler de início é disparado quando um prefixo de namespace entra em escopo, e este handler de fim é disparado quando esse prefixo sai do escopo.
Esta função pertence à extensão xml (SAX) orientada a eventos do PHP, que lê um documento de cima para baixo e chama os seus handlers conforme encontra cada construção, em vez de construir uma árvore na memória como o SimpleXML. É mais útil quando você deseja rastrear quais namespaces estão ativos durante a análise — por exemplo, para manter uma pilha de prefixos em escopo ou para limpar o estado assim que uma seção com namespace termina.
Quando usar
Uma declaração de namespace é um atributo como xmlns:ns="http://example.com". Seu escopo é o elemento em que aparece e todos os seus descendentes. Use o handler de fim de namespace quando você precisar saber o momento exato em que esse escopo se fecha — geralmente para retirar um prefixo da pilha criada no handler de início, espelhando como o próprio parser gerencia o escopo.
Sintaxe
xml_set_end_namespace_decl_handler(XMLParser $parser, callable|false $handler): bool| Parâmetro | Descrição |
|---|---|
$parser | O parser XML, criado com xml_parser_create_ns() (recomendado) ou xml_parser_create(). |
$handler | O callback a ser executado em cada evento de fim de namespace, ou false para remover um handler previamente definido. |
Valor de retorno: retorna true em caso de sucesso e false em caso de falha (por exemplo, se $parser não for um parser válido).
Seu handler recebe dois argumentos:
function handler(XMLParser $parser, string $prefix): void$prefix é o prefixo de namespace cujo escopo está terminando (uma string vazia "" para uma declaração padrão xmlns="..."). Observe que, diferente do handler de início, o handler de fim não recebe o URI do namespace — apenas o prefixo.
Exemplos de uso
Exemplo: Definindo um handler de fim de declaração de namespace
Este exemplo configura o handler e o aciona ao analisar uma pequena string XML. O handler é invocado durante xml_parse(), quando o parser fecha o elemento que declarou o namespace.
Analisando XML com um handler de fim de declaração de namespace
function handle_end_namespace_decl($parser, $prefix) {
echo "End of namespace prefix: $prefix\n";
}
$xml_parser = xml_parser_create_ns();
xml_set_end_namespace_decl_handler($xml_parser, "handle_end_namespace_decl");
$xml_data = '<?xml version="1.0"?><root xmlns:ns="http://example.com"><ns:child/></root>';
xml_parse($xml_parser, $xml_data, true);
xml_parser_free($xml_parser);O prefixo ns é declarado em <root>, portanto seu escopo termina quando </root> é alcançado. Quando o handler é disparado, ele imprime o prefixo que saiu do escopo:
End of namespace prefix: nsAtenção: o disparo do handler de namespace de fim é sensível à versão do
libexpat/PHP — em algumas versões do PHP o handler de início é executado enquanto o de fim não. Sempre teste com o seu ambiente de execução alvo e nunca dependa somente do handler de fim para detectar um namespace; use-o em conjunto com o handler de início (abaixo) para manter seu estado consistente.
Exemplo: Combinando handlers de início e fim para rastrear escopo
Em parsers reais, o handler de fim raramente é usado sozinho. Combiná-lo com o handler de início permite manter uma pilha dos prefixos atualmente em escopo. O handler de início empilha cada prefixo quando ele entra em escopo; o handler de fim o remove quando o elemento declarante é fechado:
Rastreando prefixos de namespace em escopo com uma pilha
$activePrefixes = [];
function on_start_ns($parser, $prefix, $uri) {
global $activePrefixes;
$activePrefixes[] = $prefix;
echo "Enter '$prefix' -> $uri | active: " . implode(', ', $activePrefixes) . "\n";
}
function on_end_ns($parser, $prefix) {
global $activePrefixes;
array_pop($activePrefixes);
echo "Leave '$prefix' | active: " . implode(', ', $activePrefixes) . "\n";
}
$parser = xml_parser_create_ns();
xml_set_start_namespace_decl_handler($parser, "on_start_ns");
xml_set_end_namespace_decl_handler($parser, "on_end_ns");
$xml = '<?xml version="1.0"?>'
. '<a xmlns:x="urn:x"><b xmlns:y="urn:y"><c/></b></a>';
xml_parse($parser, $xml, true);
xml_parser_free($parser);O prefixo x é declarado em <a> e y no <b> interno. À medida que os escopos abrem e fecham, a pilha rastreia quais prefixos estão ativos. Os eventos de fim são disparados em ordem LIFO — y (o interno) sai do escopo antes de x:
Enter 'x' -> urn:x | active: x
Enter 'y' -> urn:y | active: x, y
Leave 'y' | active: x
Leave 'x' | active: Este padrão de início/remoção da pilha é o uso canônico do handler de fim: mantém sua visão dos namespaces em escopo alinhada com o gerenciamento de escopo do próprio parser.
Erros comuns
- Use
xml_parser_create_ns(). Os handlers de namespace só recebem eventos quando o parser é ciente de namespaces. Um parser criado com o simplesxml_parser_create()não separará prefixos de URIs. - Sem URI no callback de fim. Se você precisar do URI quando o escopo fechar, capture-o no handler de início (indexado pelo prefixo) e consulte-o aqui.
- Defina os handlers antes de analisar. Registre o handler antes da primeira chamada a
xml_parse(); handlers definidos no meio da análise perderão os eventos anteriores. - Libere o parser. Chame
xml_parser_free()ao terminar para liberar recursos, especialmente em scripts de longa execução.
Conclusão
xml_set_end_namespace_decl_handler() permite que um parser SAX informe ao seu código exatamente quando um prefixo de namespace XML sai do escopo. Combinado com xml_set_start_namespace_decl_handler() e um parser ciente de namespaces criado com xml_parser_create_ns(), oferece controle preciso e de baixo consumo de memória sobre o escopo de namespaces ao percorrer grandes documentos XML.