PHP para Iniciantes: Estruturas de Controle - WHILE

Agora que já zeramos a primeira estrutura condicional, if, chegou a hora de trabalharmos com laços de repetição. Dentre as estruturas existentes está a que iremos bisbilhotar agora, mas antes de ir direto nela, que tal refletirmos?

Refletindo Eu espero que ninguém tenha sacado essa...

Quando desejamos criar um laço de repetição, geralmente queremos repetir baseado em uma condição. Por exemplo:

  • aperte esse parafuso até ficar bem firme;
  • ande cinco ruas e depois vire à direita;
  • mexa a mistura por 10 minutos;
  • etc.

O que é fato é que nós nunca planejamos um laço sem fim. Acabamos sempre definindo uma condição, mesmo que ela nunca seja finalizada (caso dos loops infinitos). Se você naturalmente já faz isso, por que seria diferente na programação?

Então já coloca na cabeça: todo laço tem uma condição. Se a condição é testada antes, depois, se é baseado nos dados de entrada, etc, aí sim depende do laço.

Para o artigo de hoje, o primeiro exemplo semântico que citei é o que melhor se encaixa. Vamos escrever isso em portugol:

ENQUANTO (! parafuso->estaFirme())
FAÇA parafuso->apertar();

Faz sentido? Sinceramente, acho que seria melhor um do-while, mas isso fica para o próximo artigo. O fato é: você vai repetir aquela ação até o retorno de parafuso->estaFirme() ser true.

Parafusa...

Dito isso, a frase semântica da estrutura WHILE é ENQUANTO (isso) FAÇA (aquilo). E assim como if, o PHP omite o verbo faça, ficando duas possíveis sintaxes:

Com chaves

while ( $expressao ) {
    // faça alguma coisa
}

Procedural

Obs.: esse é um termo que eu inventei, esqueci de avisar no artigo anterior. Na documentação oficial apenas chamam de sintaxe alternativa... E tá certo, a primeira também é procedural, é só que a gente escreve o fim por extenso e me lembra linguagens mais antigas... Perdão, sociedade...

while ( $expressao ):
    // faça alguma coisa
endwhile;

Kiko, dá pra fazer um laço de repetição só com if?

Se você puder fazer uma função recursiva, sim!

Por exemplo, vamos criar uma loucura classe Parafuso que vai implementar aquelas funções que mencionei anteriormente.

<?php // Parafuso.php
class Parafuso
{
    private int $apertos = 0;
    private const APERTOS_NECESSARIOS = 3;

    public function estaFirme(): bool
    {
        return $this->apertos >= static::APERTOS_NECESSARIOS;
    }

    public function apertar(): void
    {
        $this->apertos++;
    }
}

Agora podemos incluir essa classe e fazer aquele laço com while:

<?php // index.php ao lado de Parafuso.php
include_once __DIR__ . "/Parafuso.php";

$parafuso = new Parafuso;

while(! $parafuso->estaFirme()) {
    var_dump($parafuso->estaFirme()); // bool(false), 3 vezes seguidas
    $parafuso->apertar();
}
var_dump($parafuso->estaFirme()); // bool(true)

Agora nós podemos re-criar esse while em forma de função recursiva (função que chama a si mesmo, gerando um laço de repetição):

<?php // apertar_parafuso_func.ph
function apertar_parafuso(Parafuso $parafuso): void
{
    if ($parafuso->estaFirme()) {
        return;
    }
    // colocando o var_dump no mesmo ponto do while, antes de apertar
    var_dump($parafuso->estaFirme()); // bool(false), 3 vezes
    $parafuso->apertar();
    apertar_parafuso($parafuso); // a recursão está aqui
}

E agora alteramos o index para ficar:

<?php // index.php ao lado de Parafuso.php e apertar_parafuso_func.php
include_once __DIR__ . "/Parafuso.php";
include_once __DIR__ . "/apertar_parafuso_func.php";

$parafuso = new Parafuso;

apertar_parafuso($parafuso);

var_dump($parafuso->estaFirme()); // bool(true)

Funcionou? Bom, você pode brincar alterando a constante APERTOS_NECESSARIOS na classe Parafuso. Ela representa o número de loops.

Manda apertar aê!

Apesar de funcionar, um alerta...

Se você está lidando com milhares de repetições, recursão não é o melhor caminho. Pelo contrário, pode custar bastante! As estruturas de controle que criam laços de repetição não foram inventadas a toa, né?! Se não, a prática recomendada seria criar funções recursivas e pronto.

"Cada caso é um caso"

E mesmo sendo clichê falar essa frase, preciso mencioná-la. Capisce?

E POR HOJE É SÓ!

Curtiu?! Comenta e compartilha! Chama as minas pra codar, bilisca os manos pra estudar e invoca todes aí pra gente bater um papo massa no canal do Rafael Neris no Discord: PHP Career Mentoring. Apesar de ter PHP no título, desenvolvedores de outras linguagens também são bem vindos! Não vamos compartilhar nada pra vocês - HEHEHE - mas se vocês estão aqui, provavelmente tem algum interesse no PHP, então faz todo sentido brotar lá, beleza? A gente faz uns live coding de vez em quando e eu estou tentando separar um tempo pra organizar um coding dojo. Vai que, hein?

Dojo

E no próximo artigo, irei falar sobre a estrutura de controle de repetição que mencionei hoje: do-while. É praticamente a mesma coisa que você viu hoje, só que a condição vem depois de executar o laço... Opa, soltei um spoiler. Ainda assim, acredito que o exemplo que darei amanhã vai ser legal, então não perca!

Inté!!