PHP para Iniciantes: Estruturas de Controle - SWITCH

Switch, que não é o da Nintendo, é uma estrutura de controle que age como um chaveador, que é a tradução do termo em inglês e, portanto, é a semântica natural. Essa estrutura serve para selecionar um bloco de instruções baseado no valor de uma única expressão. Por exemplo, você já ouviu falar em chaveador de HDMI?

Até pouco tempo atrás eu desconhecia essa belezura e precisei comprar para alimentar ainda mais minha preguiça. O chaveador de HDMI serve para trocar, em um clique, a fonte de HDMI do(s) seu(s) monitor(es). Ou seja: você tem dois computadores e quer poder trocar qual está usando a um clique.

Por que eu teria dois computadores, Kiko?

Ah, sei lá! No meu caso, eu tenho meu PC pessoal e o da empresa. É um saco trocar todos os periféricos toda vez, então eu acabei deixando o da empresa sempre solitário no canto e usando minhas coisas só no meu... Até conhecer essa maravilha da humanidade, rs.

No meu caso, eu comprei um que serve para chavear não somente o HDMI, mas também os periféricos USB. Migra tudo de uma vez só: teclado, mouse, fone, mesa digitalizadora, etc.

Eu vi pela internet que a galera usa chaveadores ainda mais cabulosos pra montar todo um setup com consoles, home theathers, etc: podem controlar o que está sendo conectado naquele momento. É isso que é um switch.

Tá, mas qual semântica define melhor isso, Kiko?

Você tá ficando mal acostumado esperando minhas reflexões de semântica, hein? Cuidado hahaha...

Reflexão sobre semântica

O switch, também conhecido como switch-case, foi feito para ter várias possibilidades. Citando como caso de uso de hoje, podemos mencionar os trilhos de um trem.

Em algum momento da viagem, o trem chega em uma estação responsável por direcionar o trem para a direção que corresponde aonde ele tem de ir:

  • se o trilho está para a direita, então vai para a cidade A;
  • ou se o trilho está no meio, então vai para a cidade B;
  • ou se o trilho está para a esquerda, então vai para a cidade C;
  • em qualquer outro caso (não estiver definido, por exemplo), o trem deve parar.

Olha, não sei se os trens funcionam dessa forma não, ok? É só um exemplo. Mas você percebeu que tudo isso que mencionei são if? SE (isso) ENTÃO (aquilo)... Dá pra escrever isso como if-elseif-elseif-else.

<?php

$trilho = null;

if ($trilho === 'direita') {
    echo 'Próxima parada: cidade A!';
} elseif ($trilho === 'meio') {
    echo 'Próxima parada: cidade B!';
} elseif ($trilho === 'esquerda') {
    echo 'Próxima parada: cidade C!';
} else {
    echo 'Parando agora...';
}

Você reparou que esse cenário é estupidamente redundante? Olha quantas vezes nós escrevemos a variável $trilho sem nenhum outro critério além de seu próprio valor... Cenários como esse favorecem o uso de switch, e isso existe até na gramática! Veja como a sentença poderia estar bem mais curta, pensando como switch:

Em algum momento da viagem, o trem chega em uma estação responsável por direcionar o trem para a direção que corresponde aonde ele tem de ir. Se o trilho:

  • está para a direita, então vai para a cidade A;
  • está no meio, então vai para a cidade B;
  • está para a esquerda, então vai para a cidade C;
  • for diferente das outras opções, o trem deve parar.

Assim, eu escrevo somente um se baseado no mesmo escopo. Com isso, podemos concluir que a semântica de um switch é DADA (expressão), CASO (valor[1]) ENTÃO (ação[1]), CASO (valor[2]) ENTÃO (ação[2]), (...), CASO (valor[n]) ENTÃO (ação[n]), OU, POR PADRÃO, FAÇA (ação[n+1]).

Na prática

Eu sei que a semântica deve ter dado um flashback das aulas de matemática... É muito difícil exemplificar algo que pode crescer muito, então vamos para a prática:

PS.: o que vou escrever está propositalmente errado, é para o próximo assunto.

<?php

$trilho = null;

switch ($trilho) {
    case 'direita':
        echo 'Próxima parada: cidade A!';
    case 'meio':
        echo 'Próxima parada: cidade B!';
    case 'esquerda':
        echo 'Próxima parada: cidade C!';
    default:
        echo 'Parando agora...';
}

Ué, Kiko, eu rodei aqui o código e saiu apenas 'Parando agora...', assim como no if. O que está errado?

Bem, acontece que o switch permite que mais de um case tenha o mesmo comportamento, o que significa que você precisa informar explicitamente onde os case terminam! E como faremos isso? Usando a estrutura break no final do bloco de instruções relativo.

A prova do que falei já está ali no código. Se fizer $trilho = 'direita', o código irá imprimir todas as frases, pois nenhum tem o break no final. A sentença correta seria:

<?php
$trilho = 'direita';

switch ($trilho) {
    case 'direita':
        echo 'Próxima parada: cidade A!';
        break;
    case 'meio':
        echo 'Próxima parada: cidade B!';
        break;
    case 'esquerda':
        echo 'Próxima parada: cidade C!';
        break;
    default:
        echo 'Parando agora...';
        break;
}

Agora sim, o comportamento é o mesmo que o if, porém gastando muito mais linhas, não é mesmo?

Essa estrutura tem sintaxe procedural, Kiko?

Tem sim! E é na mesma pegada das outras estruturas:

<?php
$trilho = 'direita';

switch ($trilho):
    case 'direita':
        echo 'Próxima parada: cidade A!';
        break;
    case 'meio':
        echo 'Próxima parada: cidade B!';
        break;
    case 'esquerda':
        echo 'Próxima parada: cidade C!';
        break;
    default:
        echo 'Parando agora...';
        break;
endswitch;

Note que também é possível trocar os dois pontos (:) no final de cada case ou default por ponto-e-vírgula (;). Funciona da mesma forma.

<?php
$trilho = 'direita';

switch ($trilho) {
    case 'direita';
        echo 'Próxima parada: cidade A!';
        break;
    case 'meio';
        echo 'Próxima parada: cidade B!';
        break;
    case 'esquerda';
        echo 'Próxima parada: cidade C!';
        break;
    default;
        echo 'Parando agora...';
        break;
}

Ainda assim, prefiro com dois pontos. Não tem nenhuma diferença de comportamento nesses casos, mas o padrão da galera é com dois pontos, ok?!

Então, Kiko, o que é melhor? Vários if ou um switch?

Sinceramente, eu prefiro o if. Pensa só: sempre que estamos desenvolvendo um produto, precisamos ter em mente que qualquer coisa ali dentro pode mudar do dia pra noite. Não, o código não vai se alterar sozinho, obviamente, mas as regras de negócio do produto precisam acompanhar as evoluções do mercado. Dito isso, seu código precisa estar o mais preparado possível para ser alterado facilmente, seja por você, que escreveu, ou por qualquer outro desenvolvedor.

Dito isso, escrever um switch para determinar uma regra de negócio é absolutamente errado. Hoje a regra pode depender somente de $trilho, amanhã o trem pode voar e precisa checar isso também, saca? Tipo se tá pra esquerda no solo, cidade A, se tá pra esquerda e tá voando, cidade Z. O que você vai fazer? Um switch dentro do switch? Enfim, escrever as regras por ifs nos dá mais controle sobre isso.

ENTRETANTO, TODAVIA, PORÉM, o switch pode ser a melhor escolha para padrões de desenvolvimento que não tem ligação com a regra de negócio. Citando como exemplo, tem o Factory Pattern (post by Luan Loose). A manutenção para incluir novas classes numa fábrica fica infinitamente mais fácil nessa estrutura, por isso falo desse jeito.

Então reflita bem antes de escolher um ou outro. Beleza?!

E por hoje é só! Até pensei em re-implementar o switch em uma estrutura orientada a objeto mas, sinceramente, seria um desserviço pra humanidade, rs. Então vamos deixar como está e no próximo artigo eu falo sobre a próxima estrutura de controle, o match, que veio com tudo no PHP 8.0 e muita gente nunca nem ouviu falar. Bora?!

Inté!!