PHP switch
Quando você compara a mesma variável com uma lista de valores (o dia da semana é 1? é 2? é 3?…), um if/elseif fica longo e repetitivo. O switch foi feito para isso: você diz uma vez qual valor está examinando e lista os casos.
- A anatomia do
switch:case,breakedefault. - O que acontece quando falta um
break(o fall-through) e como usar isso a seu favor. - Vários valores levando ao mesmo bloco.
- A comparação frouxa (
==) doswitche as surpresas com"0",nulle"1e1". - O truque do
switch (true), a sintaxeendswitche os erros reais.
A ideia: a central telefônica
"Para falar com o financeiro, digite 1. Para o suporte, digite 2. Para outros assuntos, aguarde." A central olha o número que você digitou e pula direto para o atendimento certo. O switch ("chave", "interruptor" de desvio) funciona assim: olha um valor e salta para o case ("caso") correspondente.
A anatomia
<?php
$dia = 3;
switch ($dia) {
case 1:
echo "Domingo\n";
break;
case 2:
echo "Segunda\n";
break;
case 3:
echo "Terça\n";
break;
default:
echo "Outro dia\n";
}
- switch ($dia)
- O valor examinado, entre parênteses. É calculado uma vez.
- { … }
- Todos os casos ficam dentro de um par de chaves.
- case 1:
- "No caso de ser 1". Um valor seguido de dois-pontos. O PHP compara
$dia == 1. - echo …
- As linhas que rodam a partir desse caso. Não precisam de chaves.
- break;
- "Interromper": sai do
switch. Sem ele, o PHP continua rodando os casos de baixo (já, já você vê). - default:
- "Padrão": roda quando nenhum
casecombinou. É opcional, como oelse. Por costume, fica no fim.
$ php dia.php Terça
Como o PHP faz: compara $dia com o case 1 (não), com o case 2 (não), com o case 3 (sim!) e começa a rodar dali, até encontrar o break. O mesmo programa com if seria if ($dia == 1) … elseif ($dia == 2) … elseif ($dia == 3) … else …, repetindo $dia == em cada linha.
Sem break: o fall-through
O case é só um ponto de entrada, como uma porta. Depois de entrar, o PHP segue em frente, linha por linha, passando por cima dos outros case, até achar um break ou o fim do switch. Veja o que acontece quando a Ana esquece todos os break:
<?php
$dia = 2;
switch ($dia) {
case 1:
echo "Domingo\n";
case 2:
echo "Segunda\n";
case 3:
echo "Terça\n";
default:
echo "Outro dia\n";
}
$ php sem-break.php Segunda « entrou no case 2... Terça « ...e "caiu" no case 3... Outro dia « ...e no default
Esse comportamento se chama fall-through ("cair através"): a execução cai de um caso para o próximo. Nenhum erro ou aviso: o PHP acha que você quis assim. Esquecer um break é o bug mais comum com switch.
Termine todo case com break. Se um dia você quiser cair de propósito no caso de baixo, deixe um comentário dizendo isso (// continua no próximo caso), para ninguém "consertar" depois.
O lado bom: vários valores, um bloco
O fall-through tem um uso legítimo e muito comum: vários case vazios, um embaixo do outro, levando ao mesmo bloco.
<?php
$fruta = "uva";
switch ($fruta) {
case "maçã":
case "pera":
echo "Fruta de árvore\n";
break;
case "uva":
case "morango":
echo "Fruta pequena\n";
break;
default:
echo "Não sei\n";
}
$ php frutas.php Fruta pequena
O case "uva": não tem nada; a execução "cai" no case "morango":, que também não tem nada, e chega ao echo. Leia como "no caso de uva ou morango".
Missão: com $dia = 7 (sábado), o programa deve mostrar Fim de semana. Os dias 1 (domingo) e 7 (sábado) são fim de semana; os outros, dia útil. Junte case 1: e case 7: no mesmo bloco.
<?php
$dia = 7;
switch ($dia) {
case 1:
echo "Fim de semana";
break;
default:
echo "Dia útil";
}
<?php
$dia = 7;
switch ($dia) {
case 1:
case 7:
echo "Fim de semana";
break;
default:
echo "Dia útil";
}
A comparação frouxa: switch usa ==
Aqui está a maior armadilha. O switch compara com == (igualdade "frouxa", que converte os tipos), e não com === (veja Comparação (== e ===)). Na maior parte do tempo isso não aparece. Mas veja este switch, rodado com vários valores de $v:
<?php
$v = null; // troque por "0", 0, "", false, "a" e rode de novo
switch ($v) {
case 0:
echo "case 0\n";
break;
case "":
echo "case \"\"\n";
break;
default:
echo "default\n";
}
Valor de $v | Saída real | Por quê |
|---|---|---|
"0" | case 0 | "0" == 0: o texto numérico vira número |
0 | case 0 | Igual |
"" | case "" | No PHP 8, "" == 0 é false |
null | case 0 | null == 0 é true: os dois viram "falso" |
false | case 0 | false == 0 é true |
"a" | default | Nenhum caso combina |
$ php frouxo.php case 0 « com $v = null: uma variável "sem valor" entrou no caso do zero
Se $v fosse uma quantidade que não veio do formulário (null), o programa trataria como "zero itens", sem aviso nenhum. E tem um caso ainda mais estranho, com textos que parecem números:
<?php
$codigo = "1e1";
switch ($codigo) {
case "10":
echo "Código 10?!\n";
break;
default:
echo "outro\n";
}
$ php codigo.php Código 10?!
"1e1" é a notação científica de 10 (1 × 10¹). Quando os dois lados do == são textos numéricos, o PHP compara como números, e 10 == 10. Se esses fossem códigos de produto da lojinha, o produto "1e1" seria confundido com o "10".
- Garanta o tipo antes do
switch:switch ((int) $dia)para números, ouswitch ((string) $codigo)… (mas lembre: dois textos numéricos ainda se comparam como números). - Use
matchPHP 8.0+, que compara com===. É a próxima aula, e é o motivo principal de omatchexistir.
switch (true): faixas de valores
O case aceita qualquer expressão, não só valores fixos. Um truque comum é examinar true e colocar condições nos case: o primeiro cuja condição der true é escolhido.
<?php
$nota = 8;
switch (true) {
case $nota >= 7:
echo "Aprovado\n";
break;
case $nota >= 5:
echo "Recuperação\n";
break;
default:
echo "Reprovado\n";
}
$ php faixas.php Aprovado
Funciona, mas a comparação frouxa continua valendo (true == "texto" também é verdadeiro), e o if/elseif faz o mesmo de forma mais direta. Você vai ver esse truque em códigos existentes; para os seus, prefira if/elseif ou match (true).
Detalhes que você vai encontrar
Sintaxe alternativa: endswitch
Como o if, o switch tem uma forma com : e endswitch; para templates HTML (veja PHP Dentro do HTML):
<?php
$x = 1;
switch ($x):
case 1:
echo "um\n";
break;
endswitch;
$ php alternativa.php um
Na prática, é raro: no meio do HTML, um switch fica confuso. Calcule o valor antes, em PHP puro, e mostre só o resultado.
Nenhum caso e nenhum default
Se nada combinar e não houver default, o switch simplesmente não faz nada, sem aviso. (O match, ao contrário, dá erro; veja a próxima aula.)
return no lugar do break
Dentro de uma função, é comum cada case terminar com return valor;: o return sai da função inteira, então o break não é necessário.
Quando dá errado
$ php sem-break.php Segunda Terça Outro dia
O que significa: faltou break no fim de um case, e a execução caiu nos de baixo.
Como consertar: coloque break; como última linha de cada case que tem código.
<?php
$x = 1;
switch ($x) {
case 1:
echo "um\n";
break;
default:
echo "outro\n";
break;
default:
echo "de novo\n";
}
$ php dois-default.php
Fatal error: Switch statements may only contain one default clause in /home/ana/php/dois-default.php on line 10
Stack trace:
#0 {main}
O que significa: "um switch só pode ter um default". Acontece ao copiar e colar blocos. É detectado antes de rodar: nada executa.
Como consertar: deixe um só default.
: do case
<?php
$x = 1;
switch ($x) {
case 1:
echo "um\n";
break;
case 2
echo "dois\n";
}
$ php sem-dois-pontos.php Parse error: syntax error, unexpected token "echo" in /home/ana/php/sem-dois-pontos.php on line 8
O que significa: depois do valor do case, o PHP esperava :. Ele só percebe o problema na linha seguinte (8), ao encontrar o echo.
Como consertar: case 2:. (Curiosidade: case 2; com ponto e vírgula é aceito, por motivos históricos. Não use.)
<?php
$x = 1;
switch ($x) {
case 1:
echo "a\n";
continue;
}
$ php continue.php Warning: "continue" targeting switch is equivalent to "break" in /home/ana/php/continue.php on line 6 a
O que significa: "um continue que mira o switch equivale a break". Para o PHP, o switch conta como uma estrutura de repetição para o break e o continue. Isso confunde quando o switch está dentro de um laço e você queria pular para a próxima volta do laço.
Como consertar: use break para sair do switch. Para pular a volta do laço de fora, use continue 2 (veja break e continue).
$ php codigo.php Código 10?!
O que significa: a comparação frouxa (==) achou iguais valores que você considera diferentes: null e 0, "1e1" e "10", false e 0.
Como consertar: converta o valor para o tipo certo antes do switch, ou troque por match, que usa ===.
Referência
| Parte | O que faz |
|---|---|
switch (valor) { … } | Examina o valor uma vez |
case X: | Ponto de entrada quando valor == X |
case A: case B: | A ou B levam ao mesmo bloco |
break; | Sai do switch |
default: | Nenhum caso combinou (no máximo um) |
switch (true) { case $n > 5: … } | Faixas de valores |
switch (…): … endswitch; | Sintaxe alternativa |
| Comparação | == (frouxa) |
Exercícios
1. Sair do caso
Complete a palavra que impede a execução de cair no próximo case:
2. Nenhum caso
Complete com a palavra do caso "padrão":
3. Com $n = 1, o que mostra switch ($n) { case 1: echo "A"; case 2: echo "B"; break; case 3: echo "C"; }?
4. Com $v = null, em qual caso o switch ($v) entra, se houver case 0: e default:?
5. Que tipo de comparação o switch usa?
Missão final: na lojinha, o pagamento "pix" deve mostrar Pagamento por PIX e, na linha de baixo, Desconto de 5%; "cartao" mostra Pagamento no cartão; qualquer outro, Forma desconhecida. O código abaixo tem um bug: rode com $pagamento = "pix" e veja o que sobra na saída. Corrija.
<?php
$pagamento = "pix";
switch ($pagamento) {
case "pix":
echo "Pagamento por PIX\n";
echo "Desconto de 5%\n";
case "cartao":
echo "Pagamento no cartão\n";
break;
default:
echo "Forma desconhecida\n";
}
<?php
$pagamento = "pix";
switch ($pagamento) {
case "pix":
echo "Pagamento por PIX\n";
echo "Desconto de 5%\n";
break;
case "cartao":
echo "Pagamento no cartão\n";
break;
default:
echo "Forma desconhecida\n";
}
Resumo
switchexamina um valor e salta para ocaseigual;defaulté o "nenhum dos anteriores".- Cada
caseé só uma porta de entrada: sembreak, a execução cai nos casos de baixo (fall-through). cases vazios empilhados = "este ou aquele".- O
switchcompara com==:nullefalseentram nocase 0,"1e1"entra nocase "10". - Para comparação estrita e código mais curto, o PHP 8 tem o
match: a próxima aula.