preg_match($pattern, $subject, $matches) verifica se uma string bate com uma expressão regular. Ele retorna 1 quando bate e 0 caso contrário, e preenche $matches com o que encontrou: preg_match('/\d+/', 'Order 4521 shipped', $m) retorna 1 e define $m[0] como "4521".
O padrão é uma string com delimitadores em volta, normalmente /.../, seguida de modificadores como i. Escreva padrões entre aspas simples: dentro de aspas duplas o PHP primeiro expande $name e escapes como \x41 ou \101, então o motor de regex pode receber um padrão diferente do que você digitou.
Grupos de captura
Parênteses num padrão capturam a parte da string com que batem. $m[0] é a correspondência inteira, $m[1] o primeiro grupo, $m[2] o segundo, contados pelo parêntese de abertura a partir da esquerda.
Grupos nomeados
(?<name>...) dá um nome a um grupo. O valor é guardado sob o nome e sob o número, então o código que lê o resultado não quebra quando alguém adiciona um grupo antes no padrão.
Encontrar todas as correspondências com preg_match_all
O preg_match_all() continua procurando depois da primeira correspondência e retorna o número de correspondências. Por padrão, $m[0] guarda todas as correspondências completas e $m[1] todos os valores do primeiro grupo. Com PREG_SET_ORDER você recebe um array por correspondência, o que é mais fácil de percorrer.
Validar entradas: âncoras, telefones, códigos postais
Para validação, o padrão precisa bater com a string inteira, então comece com ^ e termine com $. Uma armadilha: $ também bate antes de uma quebra de linha final, então '/^\d+$/' aceita "123\n". Adicione o modificador D, ou use \z, que só bate no fim exato.
Para endereços de e-mail, uma regex ou rejeita endereços válidos ou aceita inválidos. Use filter_var($email, FILTER_VALIDATE_EMAIL) no lugar (veja filter_var()).
O modificador u para UTF-8 e texto japonês
Sem o modificador u, um padrão trabalha com bytes. Um caractere japonês tem três bytes em UTF-8, então . bate com um terço de um caractere e os tamanhos saem errados. Com u, o padrão trabalha com caracteres e você pode usar classes de propriedades Unicode.
O u também valida o texto: se a string não for UTF-8 válido, o preg_match() retorna false em vez de procurar.
Escapar entradas do usuário com preg_quote
Caracteres como ., +, ?, ( e / têm significado especial num padrão. Se parte do padrão vem de uma variável, como um termo de busca, passe-a pelo preg_quote() com o delimitador como segundo argumento, senão 1+1 vai bater com 11 e uma / sem escape quebra o padrão.
Um padrão inválido não lança exceção. O PHP imprime um aviso e o preg_match() retorna false:
Warning: preg_match(): No ending delimiter '/' found in /path/to/index.php on line 3
Então verifique === false (ou preg_last_error_msg()) quando o padrão é montado em tempo de execução. Para uma simples verificação de substring sem padrão nenhum, o str_contains() é mais rápido e mais claro. Para alterar o texto encontrado, use o preg_replace().
Perguntas frequentes
O que o preg_match retorna no PHP?
1 se o padrão bate, 0 se não bate, e false se o próprio padrão é inválido. Como 0 e false são falsos, compare com === 1 quando precisar distinguir um padrão quebrado de nenhuma correspondência.
Como pego o texto encontrado pelo preg_match?
Passe um terceiro argumento: preg_match('/(\d+)/', 'Order 4521', $m). Então $m[0] é a correspondência inteira e $m[1] o primeiro grupo de captura, os dois "4521" aqui. Com um grupo nomeado (?<id>\d+), o valor também fica em $m['id'].
Qual a diferença entre preg_match e preg_match_all?
O preg_match() para na primeira correspondência. O preg_match_all() encontra todas, retorna quantas encontrou e preenche $matches com todas elas: preg_match_all('/\d+/', 'a1 b22 c333', $m) retorna 3 e $m[0] é ["1", "22", "333"].
Como uso preg_match com texto acentuado, japonês ou outro UTF-8?
Adicione o modificador u: preg_match('/^.{3}$/u', '日本語') retorna 1. Sem u, o PHP trata a string como bytes, então . bate com um byte de um caractere de 3 bytes. Com u você também pode usar classes Unicode como \p{Han}, \p{Hiragana} e \p{Katakana}.
Como verifico se uma string contém só números no PHP?
preg_match('/^\d+$/D', $s) ou, sem regex, ctype_digit($s). O modificador D (ou \z no lugar de $) importa: um $ simples também aceita uma quebra de linha final, então "123\n" passaria.