PHP match PHP 8.0+
O match chegou no PHP 8.0 para resolver os problemas do switch: nada de break esquecido, nada de comparação frouxa, e o resultado é um valor que você guarda direto numa variável. Para escolher um valor a partir de outro, é a ferramenta mais moderna e segura do PHP.
- A anatomia do
match: braços com=>, vírgulas edefault. - Por que ele é uma expressão (devolve valor) e o
switchnão. - A comparação estrita (
===): adeus às surpresas com"0",nulle"1e1". - Vários valores no mesmo braço.
- O
UnhandledMatchError: o erro que aparece quando nenhum braço combina. - O
match (true)para faixas de valores, e a tabelamatch×switch.
A ideia: uma tabela de consulta
Pense na tabela de frete pendurada na parede dos Correios: na coluna da esquerda, a região; na da direita, o preço. Você procura a sua linha e lê a resposta. O match ("combinar", "corresponder") é essa tabela escrita em PHP: cada linha tem um valor à esquerda e o resultado à direita, e o match devolve o resultado da linha que combinar exatamente.
A anatomia
<?php
$dia = 3;
$nome = match ($dia) {
1 => "Domingo",
2 => "Segunda",
3 => "Terça",
default => "Outro dia",
};
echo $nome, "\n";
- $nome = match ($dia)
- O valor examinado, entre parênteses. O
matchinteiro vale alguma coisa, e esse valor vai para$nome. - { … }
- Os braços (em inglês, arms), entre chaves.
- 1 => "Domingo",
- Um braço: à esquerda da seta
=>, o valor a comparar; à direita, o resultado. Termina com vírgula (não ponto e vírgula). - default => "Outro dia",
- O braço para "nenhum dos anteriores". Opcional, mas veja o que acontece sem ele.
- };
- O
;depois da chave termina o comando de atribuição ($nome = …;). A vírgula do último braço é opcional, mas recomendada.
$ php dia.php Terça
Compare com o mesmo programa em switch: aquele tinha 13 linhas, quatro break e um echo repetido em cada caso. O match tem um braço por linha e nenhum break: ele nunca cai no braço de baixo. Encontrou, devolveu, acabou.
A seta => é a mesma dos arrays associativos, e a semelhança é proposital: um match é quase um array de "chave → resultado", só que com mais poderes.
Uma expressão: pode ir em qualquer lugar
Como o ternário, o match é uma expressão. Ele pode ir direto num echo, num return, como argumento de função:
<?php
$dia = 7;
echo match ($dia) {
1, 7 => "Fim de semana",
default => "Dia útil",
}, "\n";
$ php direto.php Fim de semana
Vários valores no mesmo braço
Na linha 1, 7 => "Fim de semana", os valores à esquerda estão separados por vírgula: "se for 1 ou 7". É o equivalente aos case empilhados do switch, numa linha só.
Missão: a lojinha da Ana cobra frete por estado: "SP", "RJ", "MG" e "ES" pagam "10,00"; "PE", "PB", "RN" e "CE" pagam "15,00"; os outros estados, "25,00". Complete o match para, com $uf = "PB", mostrar Frete: R$ 15,00.
<?php
$uf = "PB";
$frete = match ($uf) {
"SP", "RJ", "MG", "ES" => "10,00",
default => "25,00",
};
echo "Frete: R$ $frete";
<?php
$uf = "PB";
$frete = match ($uf) {
"SP", "RJ", "MG", "ES" => "10,00",
"PE", "PB", "RN", "CE" => "15,00",
default => "25,00",
};
echo "Frete: R$ $frete";
Comparação estrita: ===
O match compara com ===: valor e tipo precisam ser iguais (veja Comparação (== e ===)). As surpresas da aula de switch desaparecem:
<?php
$opcao = "1";
echo match ($opcao) {
1 => "número 1",
"1" => "texto 1",
}, "\n";
$v = null;
echo match ($v) {
0 => "zero",
null => "nulo",
}, "\n";
$codigo = "1e1";
echo match ($codigo) {
"10" => "Código 10",
"1e1" => "Código 1e1",
}, "\n";
$ php estrito.php texto 1 « "1" (string) não é 1 (int) nulo « null não é 0 Código 1e1 « "1e1" não é "10"
A contrapartida: dados de formulário chegam sempre como texto. Se $_GET['dia'] vale "3", o braço 3 => não combina. Converta antes, de propósito: match ((int) $_GET['dia']). Também não há meio-termo para maiúsculas: match ("Ana") não combina com "ana" =>; use mb_strtolower antes se for o caso (veja mbstring).
Nenhum braço combinou: UnhandledMatchError
O switch sem default simplesmente não faz nada quando nenhum caso combina. O match não aceita isso: como ele precisa devolver um valor, se nada combinar ele lança um erro.
<?php
$fruta = "kiwi";
echo match ($fruta) {
"maçã", "pera" => "Fruta de árvore",
"uva", "morango" => "Fruta pequena",
};
$ php kiwi.php
Fatal error: Uncaught UnhandledMatchError: Unhandled match case 'kiwi' in /home/ana/php/kiwi.php:3
Stack trace:
#0 {main}
thrown in /home/ana/php/kiwi.php on line 3
- UnhandledMatchError
- O nome do erro: "erro de match não tratado".
- Unhandled match case 'kiwi'
- "Caso não tratado:
'kiwi'". O PHP mostra o valor que não encontrou braço. Com números, aparece sem aspas:Unhandled match case 5. - :3 / on line 3
- A linha onde o
matchcomeça. - Uncaught
- "Não capturado": dá para "capturar" esse erro com
try/catch(veja Exceções). Sem isso, o programa para.
Isso é uma vantagem, não um defeito. Se um valor inesperado aparece (um estado novo, um código digitado errado), o switch esconde o problema; o match avisa na hora, apontando a linha e o valor. Quando "nenhum dos anteriores" é uma situação normal, coloque um default.
match (true): faixas de valores
Para faixas (nota maior que 9, maior que 7…), examine true e coloque condições à esquerda dos braços. O primeiro braço cuja condição for true (exatamente true, por causa do ===) é escolhido:
<?php
$nota = 8.5;
$conceito = match (true) {
$nota >= 9 => "A",
$nota >= 7 => "B",
$nota >= 5 => "C",
default => "D",
};
echo "Conceito $conceito\n";
$ php conceito.php Conceito B
Os braços são testados de cima para baixo, como no elseif, então a ordem importa: comece pela faixa mais alta. É a forma mais enxuta de classificar valores em faixas, e substitui bem o switch (true) e as cadeias de elseif que só escolhem um valor.
O lado direito pode ser qualquer expressão
À direita da seta pode ir qualquer coisa que produza um valor: uma conta, uma concatenação, a chamada de uma função.
<?php
$acao = "sair";
match ($acao) {
"entrar" => print("Bem-vinda!\n"),
"sair" => print("Até logo!\n"),
};
$ php acoes.php Até logo!
Aqui o match foi usado só pelo efeito (mostrar algo), e o valor devolvido foi ignorado. Funciona com print, que é uma expressão, mas não com echo, que é um comando (veja os erros abaixo). Se cada caso precisa executar várias linhas, use if ou switch: o lado direito do match é uma expressão só.
match × switch
match 8.0+ | switch | |
|---|---|---|
| Tipo | Expressão: devolve um valor | Comando: executa linhas |
| Comparação | === (estrita) | == (frouxa) |
break | Não existe; nunca "cai" no próximo | Obrigatório para não cair (fall-through) |
| Vários valores | 1, 7 => … | case 1: case 7: |
| Nada combinou | UnhandledMatchError (se não houver default) | Não faz nada, em silêncio |
| Cada caso | Uma expressão | Quantas linhas quiser |
| Separador | Vírgula depois de cada braço | : depois do case, ; nos comandos |
| PHP antigo | Só do 8.0 em diante | Todas as versões |
Qual usar?
| Situação | Use |
|---|---|
| Escolher um valor a partir de outro | match |
| Classificar em faixas, escolhendo um valor | match (true) |
| Cada caso executa várias linhas diferentes | if/elseif ou switch |
| Dois caminhos só | if/else ou ternário |
| Código que precisa rodar em PHP 7 | switch ou if |
Experimente: troque $nota por vários valores (10, 7, 4.9) e veja o conceito. Depois apague o braço default e rode com nota 2 para ver o UnhandledMatchError.
<?php
$nota = 6.5;
$conceito = match (true) {
$nota >= 9 => "A",
$nota >= 7 => "B",
$nota >= 5 => "C",
default => "D",
};
echo "Nota $nota: conceito $conceito\n";
Quando dá errado
<?php
$x = 5;
echo match ($x) {
1 => "um",
2 => "dois",
};
$ php cinco.php
Fatal error: Uncaught UnhandledMatchError: Unhandled match case 5 in /home/ana/php/cinco.php:3
Stack trace:
#0 {main}
thrown in /home/ana/php/cinco.php on line 3
O que significa: nenhum braço combinou com o valor 5 e não há default.
Como consertar: se o valor é válido, acrescente o braço que falta. Se "qualquer outro" é normal, acrescente default => …. Se você esperava que combinasse, confira o tipo: "5" (texto) não combina com 5 =>.
<?php
$x = 5;
echo match ($x) {
1 => "um"
2 => "dois",
};
$ php sem-virgula.php Parse error: syntax error, unexpected integer "2", expecting "}" in /home/ana/php/sem-virgula.php on line 5
O que significa: sem a vírgula no fim da linha 4, o PHP achou que o match tinha acabado e esperava o }; encontrou o 2 da linha 5.
Como consertar: cada braço termina com vírgula. Quem vem do switch às vezes coloca ;, que também dá Parse error.
<?php
$x = 1;
match ($x) {
1 => echo "um",
};
$ php com-echo.php Parse error: syntax error, unexpected token "echo" in /home/ana/php/com-echo.php on line 4
O que significa: à direita da seta só cabe uma expressão; echo é um comando. Coloque o echo por fora: echo match ($x) { 1 => "um", };.
O mesmo erro aparece quando falta o ; depois do } do match e a linha seguinte começa com echo:
<?php
$x = 1;
$r = match ($x) {
1 => "um",
}
echo $r;
$ php sem-ponto.php Parse error: syntax error, unexpected token "echo" in /home/ana/php/sem-ponto.php on line 6
Como consertar: };. O match é uma expressão dentro de um comando, e o comando precisa terminar com ;.
<?php
$x = 1;
$r = match ($x) {
1 => "um",
default => "outro",
default => "de novo",
};
$ php dois-default.php
Fatal error: Match expressions may only contain one default arm in /home/ana/php/dois-default.php on line 6
Stack trace:
#0 {main}
Como consertar: um default só.
Referência
| Forma | Exemplo |
|---|---|
| Básico | $r = match ($x) { 1 => "um", 2 => "dois", }; |
| Vários valores | 1, 7 => "fim de semana", |
| Padrão | default => "outro", |
| Faixas | match (true) { $n >= 7 => "B", … } |
Direto no echo | echo match ($x) { … }; |
| Comparação | === |
Nada combinou, sem default | UnhandledMatchError |
Exercícios
1. A seta
Complete o braço com o símbolo que separa valor e resultado:
2. Dois valores, um braço
Complete para "S" e "s" darem o mesmo resultado:
3. Com $x = "2", o que match ($x) { 2 => "dois", default => "outro" } devolve?
4. O que acontece quando nenhum braço combina e não há default?
5. Qual destas afirmações é verdadeira?
Missão final: reescreva a classificação de estoque com match (true): 0 → esgotado; de 1 a 4 → poucas unidades; 5 ou mais → disponível. Com $estoque = 3, a saída deve ser Quantidade: poucas unidades.
<?php
$estoque = 3;
if ($estoque === 0) {
$situacao = "esgotado";
} elseif ($estoque < 5) {
$situacao = "poucas unidades";
} else {
$situacao = "disponível";
}
echo "Quantidade: $situacao";
<?php
$estoque = 3;
$situacao = match (true) {
$estoque === 0 => "esgotado",
$estoque < 5 => "poucas unidades",
default => "disponível",
};
echo "Quantidade: $situacao";
Resumo
match(PHP 8.0+) é uma expressão:$r = match ($x) { valor => resultado, … };.- Compara com
===: tipo e valor. Converta dados de formulário antes. - Não tem
breaknem fall-through: o primeiro braço que combinar devolve o valor. - Vários valores por braço:
1, 7 => …. Padrão:default => …. - Nada combinou e não há
default?UnhandledMatchError, com o valor na mensagem. match (true)classifica faixas de valores, de cima para baixo.- Para escolher valores, prefira
match; para executar blocos de várias linhas,ifouswitch.