PHP

Grupos nomeados no preg_match: pare de contar índice de $matches

Regex com cinco parênteses, e a cada leitura alguém conta no dedo pra saber se a data caiu no $matches[2] ou no $matches[3]. Aí entra mais um grupo no meio da expressão e todo código que lia índice numérico passa a devolver campo trocado, sem erro nenhum pra avisar. A saída é nomear os grupos.

A sintaxe é (?<nome>)

Parseando uma linha de erro do nginx, no PHP 8.3:

$linha = '2026/08/31 04:12:07 [error] 2187#0: *45 open() failed';
$re = '#^(?<data>d{4}/d{2}/d{2}) (?<hora>d{2}:d{2}:d{2}) [(?<nivel>w+)] (?<pid>d+)#';

if (preg_match($re, $linha, $m)) {
    printf("%s %s | nivel %s | pid %dn", $m['data'], $m['hora'], $m['nivel'], $m['pid']);
}

O PCRE continua preenchendo os índices numéricos junto com os nomes, então $m[1] ainda existe e vale o mesmo que $m['data']. Dá pra migrar uma expressão antiga aos poucos, nomeando um grupo por vez, sem quebrar quem já lê por número. A forma (?P<nome>...) faz exatamente a mesma coisa, é herança do Python. Nome de grupo aceita letra, número e underline, e não pode começar com dígito.

A armadilha do grupo opcional

$re = '/utm_source=(?<origem>w+)(?:&utm_medium=(?<meio>w+))?/';
preg_match($re, 'utm_source=google', $m, PREG_UNMATCHED_AS_NULL);
var_dump($m['meio']); // NULL, e nao "Undefined array key"

Sem a flag PREG_UNMATCHED_AS_NULL, grupo que não casou no fim da expressão nem entra no array, e o seu $m['meio'] vira um Warning: Undefined array key no PHP 8. Pior: grupo opcional no meio da expressão vem como string vazia, que passa batido em isset(). Com a flag, todo grupo declarado aparece no array, valendo null quando não casou.

Regra que adotei aqui: passou de dois grupos, nomeia. Quem for mexer na regex daqui a seis meses lê sozinho.

Post Recentes

Criar swapfile no Ubuntu: parar o OOM killer de matar o MySQL

VPS de 2 GB onde o mysqld morre de madrugada e o site volta com erro de conexão. Como confirmar…

5 horas atrás

Token de integração da API do Magento 2: gerar e usar no header Bearer

Erro The consumer isn't authorized to access resources ao chamar a REST do Magento 2.4.8? Ative a integração, libere os…

23 horas atrás

Rate limit no wp-login.php com nginx: barrar força bruta antes do PHP

Bots batendo centenas de POST por minuto no login derrubam a CPU. Configure limit_req_zone no nginx e devolva 429 antes…

2 dias atrás

Anonimizar IP no nginx: mascarar o último octeto do log para a LGPD

Seu access.log guarda o IP inteiro dos visitantes há meses sem necessidade. Mascare o último octeto com map e log_format…

3 dias atrás

Prompt injection em campo de usuário: isole a observação do pedido

A observação do pedido chegou com ordem embutida para gerar cupom. Delimite o texto do cliente e trate a resposta…

3 dias atrás

Preço promocional em massa no WooCommerce: agendar a Black Friday pelo WP-CLI

Um CSV com SKU e preço, um wp eval-file que agenda início e fim da promoção guardando o estado anterior,…

3 dias atrás