O PHP está discutindo pattern matching. Sim, com o operador is.
A RFC de Larry Garfield e Ilija Tovilo propõe uma nova sintaxe onde você escreve algo como $valor is int ou $response is Response(status: 200..299) e o resultado é um booleano. O operador sozinho já é útil. Mas o que ele destranca vai além.
Pattern matching existe em Rust, Python, C#, Scala, Swift. É o tipo de feature que muda como você lida com dados complexos. Em vez de encadear if/elseif com instanceof e isset e type checks manuais, você descreve a forma que o dado precisa ter. Se encaixa, true. Se não, false. E de quebra, pode extrair valores para variáveis no processo.
A RFC faz parte de um épico maior: Algebraic Data Types no PHP. Que inclui tagged unions, value types, destructuring. Pattern matching é a peça que viabiliza tudo isso.
Ainda está em discussão, não em votação. Mas o fato de ter dois dos maiores contribuidores do core assinando juntos sinaliza que é sério. Não é uma proposta exploratória. Tem implementação, tem semântica definida, tem comparação com 8 linguagens diferentes.
Isso não muda nada hoje. Mas muda o tipo de conversa sobre a linguagem. PHP 8.5 trouxe pipe operator. 8.6 traz partial application. Se pattern matching entrar em 8.7 ou 9.0, o PHP de 2028 vai ser estruturalmente diferente do que se escreve hoje.
E honestamente, esse é o tipo de evolução que faz a diferença entre "usamos PHP porque já funciona" e "escolhemos PHP porque faz sentido".
Descrever a forma no ponto do branch
O ganho operacional aparece quando a forma aceita fica ao lado da ramificação que a usa. Hoje um endpoint que recebe array misturado com DTO faz instanceof, isset, is_int, array_key_exists e atribuições manuais. O leitor reconstrói o contrato depois de oito linhas. O autor também, seis meses depois.
Com $payload is ['user' => $user & AuthenticatedUser(role: 'admin'), ...], o contrato cabe numa expressão. Binding só ocorre se o padrão inteiro casar. Variável pré-existente permanece se falhar. Isso reduz uma classe de bug em que o código extrai $id e só depois descobre que o restante era inválido.
Object patterns leem propriedades acessíveis no escopo. Hook get dispara. Propriedade não inicializada gera erro. __get entra na comparação. Isso importa para código com hooks e para objetos incompletos de ORM. Um padrão Point(x: 3, y: $y) não é um isset silencioso.
Padrões de array associativo ignoram ordem de chaves e tratam chave ausente sem warning de undefined, ao contrário de $foo['c'] === 3. Padrões posicionais, na implementação atual discutida, se aproximam de chaves numéricas sequenciais; os autores ainda pedem opinião se devem chamar array_is_list() internamente, o que tem custo. Quem hoje compara arrays com === e depende da ordem precisa saber que o operador não é um sinônimo.
mixed funciona como curinga: a chave ou a propriedade precisa existir, o valor pode ser qualquer. Útil para "este campo veio, eu ainda não decido o tipo". Literal, constante de classe, união | e interseção & (em DNF, como nos tipos) entram no mesmo sistema. Dois padrões com binding não podem ser ORed, porque a variável ficaria indefinida conforme o braço.
match() e os pontos ainda abertos
A RFC sugere duas grafias para match(): match ($var) is { ... } aplicando padrão em todos os braços, ou is em cada arm para misturar igualdade e padrão. Os autores estão divididos. Ruby mistura menos; a maior parte das linguagens pesquisadas é sempre-padrão. Esse detalhe muda o guia de estilo da equipe, então não convém copiar snippets de blog como se fossem a gramática final.
Há implementação (PR 20574 no php-src) e semântica longa. Status na wiki: em discussão, não em votação. A versão proposta no texto é PHP 8.6. Planejar "quando o 8.6 sair, reescrevemos os controllers" trata discussão como release. 8.6 já carrega outras RFCs. Esta pode escorregar, encolher ou mudar o match.
O is novo conflita com constante global ou função não-instância chamada is (case insensitive: IS, Is). Inventário de function is( e define('IS' vale mais, hoje, do que um spike de sintaxe. É o único BC break anunciado além do óbvio de uma keyword nova.
Ranges compactos, regex, captura do resto do array depois de ... e marcador de chave opcional estão em future scope. ADTs e enums com valores associados são o horizonte declarado, com posição reservada na sintaxe de objeto. Nenhum desses itens deve entrar no mesmo cartão de Jira que "estudar o operador".
Experimento local, fora do roadmap de versão
O lugar certo para brincar é um módulo isolado: validação de resposta HTTP, parsing de array de config, testes de shape em fixture. PHPUnit na versão atual continua sendo o contrato da esteira. Um fork do engine ou um polyfill mental não entra em produção.
Eu usaria a RFC como vocabulário de review. "Aqui o shape cabe num padrão" é um comentário útil mesmo sem a sintaxe. Empurra o código de hoje para early return e extração explícita. Quando (e se) o operador existir, a tradução fica mecânica. Reescrever helpers de type check "para ficar pronto" gasta sprint numa gramática que ainda pode mudar o match.
Critério de parar o experimento: se o módulo isolado não fica mais legível com a forma da RFC, o time não tem um caso de uso, tem curiosidade. Curiosidade cabe num brown bag. Não cabe num piso de versão.
Também recuso amarrar tagged unions, value types e destructuring no mesmo investimento. A RFC diz que matching é degrau. Cada degrau terá votação própria. Um architecture decision record pode registrar "acompanhamos rfc/pattern-matching; não pinamos versão". Isso é decisão. Reservar 8.7 no roadmap porque um post citou 2028 é outra coisa.
O que a proposta não cobre no código de negócio
Validação que consulta banco, política de autorização, i18n ou regra que não se expressa como padrão continua fora. O operador não substitui uma schema library nem um form request. Ele comprime checagens de forma que o programa já faz com instanceof e array_key_exists.
Código que já usa is como nome precisa de rename antes de qualquer adoção. Código que depende de warning em chave ausente para "detectar" payload malformado passa a ter silêncio no padrão associativo; a ausência vira false do is, não um notice. Isso é vantagem na maior parte dos controllers e é diferença em scripts que trataram notice como sinal.
Enquanto a discussão não vira voto, a decisão da equipe é negativa e barata: não reservar sprint, não pinar versão futura, não prometer ADT no Q3. Ler a RFC ainda vale. Ela descreve, com precisão, o tipo de dado que o PHP de produção já tenta validar na mão. Esse mapa serve hoje, na revisão de um if encadeado, mesmo que o operador demore.


