Dia 4 — Repetição: PHP e MySQL

Informatica · Conteudo · publicado em 02/10/2026
Dia 4 de 17

Repetição

Aula 1

for e while

for e while

O for repete um bloco um número controlado de vezes: inicializa o contador, testa a condição e atualiza o contador. O while repete enquanto a condição for verdadeira, sem se preocupar com quantas vezes.

for

for ($i = 1; $i <= 5; $i++) {
    echo $i;
}

As três partes vao separadas por ponto e virgula: inicializacao, condição e incremento. Qualquer uma pode ser vazia — e o que transforma o laco em for (;;), a forma infinita.

A condição e testada antes de cada volta, então um for cuja condição já começa falsa não executa nada. Esse detalhe e a diferença entre for e do-while.

for ($i = 0; $i < 5; $i++) {}   // 5 voltas: 0, 1, 2, 3, 4
for ($i = 1; $i <= 5; $i++) {}  // 5 voltas: 1, 2, 3, 4, 5

while

$tentativas = 3;
while ($tentativas > 0) {
    echo $tentativas;
    $tentativas--;
}

O while so tem condição. O corpo pode não rodar nenhuma vez: e o que acontece quando a condição já comeca falsa, como while ($x < 5) com $x = 10.

O while e a escolha quando o número de voltas não se sabe de antemao — repetir até o usuario acertar, processar fila, ler arquivo linha a linha.

Acumulador

O contador e um acumulador: uma variável que guarda o total e e atualizada a cada volta. Ela precisa ser iniciada antes do laco, senao o PHP avisa "undefined variable" na primeira volta.

$total = 0;
foreach ($precos as $preco) {
    $total += $preco;
}

O operador += encurta $total = $total + $preco. O erro classico e declarar o acumulador dentro do laco: ele volta a zero a cada volta e o total final e sempre o ultimo valor.

A mesma lógica vale para while, com $contador++ ou $contador += 2 para pular de dois em dois.

Exemplo

<?php
declare(strict_types=1);

// for: inicializacao; condicao; incremento. As tres partes vao separadas por
// ponto e virgula e podem ser vazias.
echo "1. for contando de 1 a 5\n";
for ($i = 1; $i <= 5; $i++) {
    echo "   volta $i\n";
}

// O contador pode comecar em zero e a condicao pode ser <.
echo "\n2. O mesmo laco comecando em zero\n";
$soma = 0;
for ($i = 0; $i < 5; $i++) {
    $soma += $i;
}
echo "   soma de 0 a 4 = $soma\n";

// while: so a condicao. O corpo pode nao rodar nenhuma vez.
echo "\n3. while testa a condicao antes de executar\n";
$tentativas = 3;
while ($tentativas > 0) {
    echo "   tentativa restando: $tentativas\n";
    $tentativas--;
}
echo "   o corpo rodou " . (3 - $tentativas) . " vezes\n";

// while com condicao inicialmente falsa nao entra no corpo.
$contador = 10;
while ($contador < 5) {
    echo "   isto nunca aparece\n";
}
echo "   while com $contador < 5 nao executou nada\n";

// As tres partes do for sao opcionais. Sem condicao, o laco e infinito.
echo "\n4. Partes do for opcionais\n";
for (;;) {
    echo "   primeira volta\n";
    break;
}

$lista = ['a', 'b'];
for ($i = 0, $n = count($lista); $i < $n; $i++) {
    echo '   indice ' . $i . ': ' . $lista[$i] . "\n";
}

// Acumulador: a variavel que guarda o total precisa existir antes do laco.
echo "\n5. Acumulador precisa ser inicializado fora\n";
$total = 0;
$itens = [12.50, 8.00, 30.25, 4.99];
foreach ($itens as $preco) {
    $total += $preco;
}
echo '   total dos ' . count($itens) . " itens: $total\n";

$aprovados = 0;
$notas = [7.5, 5.0, 9.9, 3.2, 6.8];
foreach ($notas as $nota) {
    if ($nota >= 6.0) {
        $aprovados++;
    }
}
echo "   notas aprovadas: $aprovados de " . count($notas) . "\n";

// while tambem acumula.
echo "\n6. while como acumulador\n";
$linha = 5;
$espaco = 1;
while ($espaco <= $linha) {
    echo str_repeat('* ', $espaco) . "\n";
    $espaco++;
}

Saída real

1. for contando de 1 a 5
   volta 1
   volta 2
   volta 3
   volta 4
   volta 5

2. O mesmo laco comecando em zero
   soma de 0 a 4 = 10

3. while testa a condicao antes de executar
   tentativa restando: 3
   tentativa restando: 2
   tentativa restando: 1
   o corpo rodou 3 vezes
   while com 10 < 5 nao executou nada

4. Partes do for opcionais
   primeira volta
   indice 0: a
   indice 1: b

5. Acumulador precisa ser inicializado fora
   total dos 4 itens: 55.74
   notas aprovadas: 3 de 5

6. while como acumulador
* 
* * 
* * * 
* * * * 
* * * * *
Aula 2

do-while e laços infinitos

do-while e laços infinitos

O do-while executa o corpo antes de testar a condição, então roda pelo menos uma vez. Quando a repeticao depende de algo externo — uma resposta do usuario, uma leitura de arquivo — essa e a forma correta, porque evita um teste vazio no comeco.

A diferença que importa

$i = 10;
while ($i < 5) { echo 'nunca'; }        // zero execucoes
$i = 10;
do { echo 'uma vez'; } while ($i < 5);   // uma execucao

Com while, a condição falsa impede a entrada. Com do-while, o corpo já rodou antes do primeiro teste. Por isso a condição precisa mudar dentro do corpo; caso contrario o laco nunca termina.

$confirmacao = 'N';
do {
    echo "digite S: ";
    $confirmacao = 'S';      // o corpo precisa mudar a condicao
} while ($confirmacao !== 'S');

while (true) e for (;;)

São a mesma coisa: laco sem condição de parada, que so sai pelo break. O while (true) e o mais comum e mais legivel.

$processados = 0;
while (true) {
    $processados++;
    if ($processados >= 4) {
        break;
    }
    echo "item $processados";
}

O break costuma ficar dentro de um if, e essa e a saída mais usada na pratica. As outras saídas de um laco são o proprio return, quando o laco esta dentro de uma função, e exit ou die, que encerram o script inteiro.

Condição composta

Quando a parada depende de duas regras, junte com && e ||. O && e avaliado primeiro, então o grupo mais restritivo vem entre parenteses:

while ($indice < count($fila) && $fila[$indice] !== '') {
    $processados[] = $fila[$indice];
    $indice++;
}

O laco que nunca termina acontece quando a condição depende de uma variável que o corpo nunca altera, ou quando o corpo altera para um valor que ainda satisfaz a condição. A defesa pratica e o limite de seguranca — um if com contador maximo — porque um laco infinito em página web trava o servidor, não so o navegador.

Exemplo

<?php
declare(strict_types=1);

// do-while testa a condicao DEPOIS de executar: o corpo roda pelo menos uma vez.
echo "1. do-while executa uma vez mesmo com condicao ja falsa\n";
$tentativas = 0;
do {
    echo "   corpo executado, tentativas = $tentativas\n";
    $tentativas++;
} while ($tentativas < 3);
echo "   total de execucoes: $tentativas\n";

// A condicao precisa virar falsa. Aqui a confirmacao muda dentro do corpo.
$confirmacao = 'N';
do {
    echo "   'Digite S para confirmar' recebido: '$confirmacao'\n";
    $confirmacao = 'S';
} while ($confirmacao !== 'S');
echo "   (o corpo rodou uma vez porque a confirmacao ja era 'S')\n";

// while nao faz isso: com condicao falsa o corpo nao roda nenhuma vez.
echo "\n2. while e do-while com a mesma condicao inicial\n";
$i = 10;
while ($i < 5) {
    echo "   isto nunca aparece\n";
}
echo "   while: zero execucoes\n";
$i = 10;
do {
    echo "   do-while: uma execucao com i = $i\n";
} while ($i < 5);

// while Infinito: e um while sem condicao de parada. O break e a saida.
echo "\n3. while (true) com break: a forma mais comum de laco infinito\n";
$processados = 0;
while (true) {
    $processados++;
    if ($processados >= 4) {
        break;
    }
    echo "   item $processados processado\n";
}
echo "   saiu do laco apos $processados itens\n";

// for (;;) tambem e infinito e as vezes deixa a intencao mais clara.
echo "\n4. for (;;) e a mesma coisa\n";
$tentativas = 0;
for (;;) {
    $tentativas++;
    if ($tentativas > 2) {
        break;
    }
    echo '   tentativa ' . $tentativas . "\n";
}
echo "   total de tentativas: $tentativas\n";

// A condicao de parada precisa depender do estado. Se ela nunca virar
// falsa, o laco so para com break, exit ou die.
echo "\n5. Laco que nunca termina: condicao sempre verdadeira\n";
$repeticoes = 0;
$limite = 3;
while ($repeticoes < $limite || $limite < 0) {
    $repeticoes++;
    if ($repeticoes >= $limite) {
        $limite = -1;   // continua verdadeiro de proposito
    }
    if ($repeticoes > 6) {
        break;          // rede de seguranca
    }
}
echo "   laco sem condicao de parada real; break de seguranca em $repeticoes voltas\n";

// Condicao composta com && e ||: e assim que se simula "enquanto houver
// item E nao deu erro".
echo "\n6. Condicao composta com && e ||\n";
$fila = ['ana', 'bruno', 'cecilia', '', 'diego'];
$indice = 0;
$processados = [];
while ($indice < count($fila) && ($fila[$indice] !== '' || $indice < 1)) {
    $processados[] = $fila[$indice];
    $indice++;
}
echo '   processados: ' . implode(', ', $processados) . "\n";

// break dentro de um if dentro do laco e o padrao de "sai quando acabou".
echo "\n7. break dentro de if: padrao para procurar em colecao\n";
$alunos = [
    ['nome' => 'Ana', 'nota' => 8.0],
    ['nome' => 'Bruno', 'nota' => 4.5],
    ['nome' => 'Cecilia', 'nota' => 9.5],
];
foreach ($alunos as $aluno) {
    if ($aluno['nota'] < 5.0) {
        echo "   reprovado encontrado: {$aluno['nome']}\n";
        break;
    }
    echo "   aprovado: {$aluno['nome']}\n";
}

Saída real

1. do-while executa uma vez mesmo com condicao ja falsa
   corpo executado, tentativas = 0
   corpo executado, tentativas = 1
   corpo executado, tentativas = 2
   total de execucoes: 3
   'Digite S para confirmar' recebido: 'N'
   (o corpo rodou uma vez porque a confirmacao ja era 'S')

2. while e do-while com a mesma condicao inicial
   while: zero execucoes
   do-while: uma execucao com i = 10

3. while (true) com break: a forma mais comum de laco infinito
   item 1 processado
   item 2 processado
   item 3 processado
   saiu do laco apos 4 itens

4. for (;;) e a mesma coisa
   tentativa 1
   tentativa 2
   total de tentativas: 3

5. Laco que nunca termina: condicao sempre verdadeira
   laco sem condicao de parada real; break de seguranca em 7 voltas

6. Condicao composta com && e ||
   processados: ana, bruno, cecilia

7. break dentro de if: padrao para procurar em colecao
   aprovado: Ana
   reprovado encontrado: Bruno
Aula 3

foreach

foreach

O foreach percorre um array sem se preocupar com índice nem com condição de parada. Ele funciona em lista indexada, em dicionario e em objeto, sempre com a mesma forma.

As três formas

foreach ($frutas as $fruta) {}                 // so os valores
foreach ($aluno as $campo => $valor) {}        // chave e valor
foreach ($tabela as [$nome, $nota]) {}         // desestrutura a linha

A forma com chave e valor e a unica que funciona bem em array associativo, onde o índice não e sequencial:

$aluno = ['nome' => 'Maria', 'idade' => 17];
foreach ($aluno as $campo => $valor) {
    echo "$campo = $valor";
}

Em array indexado a chave e o índice, e comeca em 0. Com o list(), o par índice-valor e separado em duas variáveis na mesma volta, sem precisar de =>:

foreach ($tabela as [$nome, $nota]) {
    echo "$nome tirou $nota";
}

Dentro do laco, key() devolve a chave atual e current() devolve o valor — util quando o valor vem de uma expressao e não de uma variável simples.

Ordem e alteracao

O foreach percorre na ordem de insercao das chaves, e não em ordem alfabetica nem de valor. Para ordenar, use sort(), ksort() ou usort() (aula do dia 6).

Sem o &, mudar a variável do valor dentro do laco não surte efeito no array original: o PHP entrega uma copia do valor. Para alterar o array, o & faz a variável apontar para o elemento:

foreach ($numeros as &$numero) {
    $numero *= 10;
}
unset($numero);   // obrigatorio

O unset() depois do &

Depois de um foreach com &, a referência continua apontando para o ultimo elemento. Um foreach posterior sobre outro array pode então alterar o primeiro sem querer, porque as duas voltas compartilham a mesma variável.

foreach ($primeiro as &$x) { $x *= 2; }
unset($x);              // limpa a referencia
foreach ($segundo as $y) { $y += 100; }  // agora nao toca no primeiro

O unset() imediatamente após o laco com & e o que separa o código que funciona do código que corrompe dados em producao.

Exemplo

<?php
declare(strict_types=1);

// foreach percorre valores; na forma com chave, percorre chave => valor.
$frutas = ['maçã', 'banana', 'uva'];

echo "1. foreach so nos valores\n";
foreach ($frutas as $fruta) {
    echo "   $fruta\n";
}

echo "\n2. foreach com chave e valor\n";
foreach ($frutas as $indice => $fruta) {
    echo "   [$indice] $fruta\n";
}

// A chave de um array indexado comeca em 0 e anda de 1 em 1.
echo "\n3. As chaves de um array indexado\n";
foreach ($frutas as $chave => $valor) {
    echo "   chave $chave e do tipo " . gettype($chave) . "\n";
}

// Array associativo: a chave e o que voce deu de nome.
echo "\n4. foreach em array associativo\n";
$aluno = [
    'nome'  => 'Maria',
    'idade' => 17,
    'cidade' => 'Recife',
];
foreach ($aluno as $campo => $valor) {
    echo "   $campo = $valor\n";
}

// A ordem do foreach e a ordem de insercao das chaves.
echo "\n5. A ordem e a de insercao\n";
$ordem = ['z' => 1, 'a' => 2, 'm' => 3];
foreach ($ordem as $k => $v) {
    echo "   $k => $v\n";
}

// Alternativa com list(), util quando a chave tambem interessa.
echo "\n6. list() traz indice e valor de uma vez\n";
foreach ($frutas as $indice => $fruta) {
    [$indice, $fruta] = [$indice, $fruta];
    echo "   indice $indice, fruta $fruta\n";
}

$tabela = [
    ['Ana', 8.5],
    ['Bruno', 6.0],
    ['Cecilia', 9.5],
];
foreach ($tabela as [$nome, $nota]) {
    echo "   $nome tirou $nota\n";
}

// key() dentro do laco devolve a chave atual; current() o valor.
echo "\n7. key() e current() leem a posicao atual\n";
$letras = ['a' => 'vogal', 'b' => 'consoante'];
foreach ($letras as $chave => $tipo) {
    echo '   key() = ' . key($letras) . ', current() = ' . current($letras) . "\n";
}

// Sem o &, mudar $valor dentro do laco nao altera o array original.
echo "\n8. Alterar o valor dentro do laco sem & nao surte efeito\n";
$cores = ['azul', 'verde'];
foreach ($cores as $cor) {
    $cor = strtoupper($cor);
}
echo '   depois do foreach: ' . implode(', ', $cores) . " (continua minusculo)\n";

echo "\n9. Com & o valor e alterado no proprio array\n";
$numeros = [1, 2, 3];
foreach ($numeros as &$numero) {
    $numero *= 10;
}
unset($numero);   // obrigatorio: limpa a referencia do ultimo elemento
echo '   depois do foreach: ' . implode(', ', $numeros) . "\n";

// Sem o unset, a referencia continua viva e o proximo foreach corrompe dados.
echo "\n10. Por que o unset() depois do & e obrigatorio\n";
$primeiro = [1, 2];
$segundo = [5, 6];
foreach ($primeiro as &$x) {
    $x *= 2;
}
echo '   primeiro: ' . implode(', ', $primeiro) . "\n";
foreach ($segundo as $y) {
    $y += 100;
}
echo '   segundo:  ' . implode(', ', $segundo) . " (intacto, sem referencia pendente)\n";

// foreach funciona igual em qualquer iteravel: array e objeto.
echo "\n11. foreach em lista de listas e em dicionario aninhado\n";
foreach (['nota' => 8.5, 'falta' => 0] as $chave => $valor) {
    echo "   $chave: $valor\n";
}

Saída real

1. foreach so nos valores
   maçã
   banana
   uva

2. foreach com chave e valor
   [0] maçã
   [1] banana
   [2] uva

3. As chaves de um array indexado
   chave 0 e do tipo integer
   chave 1 e do tipo integer
   chave 2 e do tipo integer

4. foreach em array associativo
   nome = Maria
   idade = 17
   cidade = Recife

5. A ordem e a de insercao
   z => 1
   a => 2
   m => 3

6. list() traz indice e valor de uma vez
   indice 0, fruta maçã
   indice 1, fruta banana
   indice 2, fruta uva
   Ana tirou 8.5
   Bruno tirou 6
   Cecilia tirou 9.5

7. key() e current() leem a posicao atual
   key() = a, current() = vogal
   key() = a, current() = vogal

8. Alterar o valor dentro do laco sem & nao surte efeito
   depois do foreach: azul, verde (continua minusculo)

9. Com & o valor e alterado no proprio array
   depois do foreach: 10, 20, 30

10. Por que o unset() depois do & e obrigatorio
   primeiro: 2, 4
   segundo:  5, 6 (intacto, sem referencia pendente)

11. foreach em lista de listas e em dicionario aninhado
   nota: 8.5
   falta: 0
Aula 4

break, continue e laços aninhados

break, continue e laços aninhados

O break sai do laco; o continue pula o resto da volta e comeca a proxima. Em laco aninhado, os dois agem no laco mais interno — e o número depois do operador escolhe quantos niveis sair ou pular.

break e continue

InstruçãoEfeito
breaksai do laco mais interno
continuepula para a proxima volta do laco mais interno
break 2sai de dois lacos
continue 2pula a volta do laco externo

O continue e o filtro de lista: descarta o item e segue.

foreach ($numeros as $n) {
    if ($n % 2 === 0) {
        continue;      // pula o par
    }
    echo $n;
}

O break e a busca: para assim que achar o que procura.

foreach ($alunos as $aluno) {
    if ($aluno['nota'] < 5.0) {
        break;         // achou o primeiro reprovado
    }
}

break 2 e continue 2

Sem número, break sai so do laco interno e o externo continua. Com 2, alcança o laco de fora.

foreach ($a as $x) {
    foreach ($b as $y) {
        if ($y === 'erro') {
            break 2;       // sai dos dois lacos
        }
    }
}

O continue 2 tem efeito diferente: ele não sai do laco externo, apenas pula o resto da volta dele e avanca para o proximo valor do externo.

foreach ($a as $x) {
    foreach ($b as $y) {
        if ($y === 2) {
            continue 2;     // pula para o proximo $x
        }
        echo "$x x $y";
    }
}

O número conta os niveis de laco, e não as repeticoes: break 3 exige três lacos aninhados.

Rotulo com goto

O goto salta para um rotulo na mesma função. E a forma de sair de varios lacos sem repeating break 2, e o unico caso em que e mais legivel que o break numerado.

for ($i = 1; $i <= 3; $i++) {
    for ($j = 1; $j <= 3; $j++) {
        if ($i * $j > 4) {
            goto fim;
        }
    }
}
fim:
echo 'saiu pelo rotulo';

O rotulo e um identificador seguido de : e precisa terminar em ; quando e um comando simples. O goto não pula para dentro de laco nem de função, e so funciona dentro da mesma função — por isso ele quase nunca substitui um break 2 bem colocado.

Exemplo

<?php
declare(strict_types=1);

// break sai do laco mais interno. continue pula para a proxima volta.
$numeros = [1, 2, 3, 4, 5, 6, 7, 8];

echo "1. break interrompe o laco\n";
foreach ($numeros as $n) {
    if ($n === 4) {
        echo "   break no $n: o 4 e os seguintes nao entram\n";
        break;
    }
    echo "  processando $n\n";
}

echo "\n2. continue pula para a proxima iteracao\n";
foreach ($numeros as $n) {
    if ($n % 2 === 0) {
        continue;
    }
    echo "   apenas impares: $n\n";
}

echo "\n3. continue no fim do corpo equivale a nada, e sautavel\n";
foreach ($numeros as $n) {
    if ($n < 3) {
        continue;
    }
    echo "   $n\n";
}

// continue 2 e break 2 dizem a quantos lacos a ordem se aplica.
echo "\n4. break 2 e continue 2 em laco aninhado\n";
foreach ([1, 2, 3] as $a) {
    foreach (['x', 'y', 'z'] as $b) {
        if ($b === 'y') {
            break 2;   // sai dos DOIS lacos de uma vez
        }
        echo "   par $a$b (o 'y' nao aparece)\n";
    }
}

echo "\n5. continue 2 pula a volta do laco de fora\n";
foreach ([1, 2, 3] as $a) {
    foreach ([1, 2, 3] as $b) {
        if ($b === 2) {
            continue 2;   // pula o resto do laco interno e vai ao proximo $a
        }
        echo "   $a x $b\n";
    }
}

// break sem numero sai so do laco onde esta.
echo "\n6. break comum em laco aninhado sai so do interno\n";
foreach ([1, 2] as $a) {
    foreach (['x', 'y'] as $b) {
        if ($b === 'x') {
            break;
        }
        echo "   interno: $a$b\n";
    }
    echo "   volta ao laco externo com a = $a\n";
}

// Rotulo: goto apontando para um rotulo dentro do laco.
echo "\n7. Rotulo com goto para interromper lacos aninhados\n";
for ($i = 1; $i <= 3; $i++) {
    for ($j = 1; $j <= 3; $j++) {
        if ($i * $j > 4) {
            goto fim;
        }
        echo "   i=$i j=$j\n";
    }
}
fim:
echo "   saiu pelo rotulo 'fim'\n";

// break 3 alcança tres niveis de aninhamento.
echo "\n8. break 3 em tres niveis\n";
$niveis = 0;
foreach ([1, 2, 3] as $a) {
    foreach ([1, 2, 3] as $b) {
        foreach ([1, 2, 3] as $c) {
            $niveis++;
            if ($niveis === 5) {
                break 3;
            }
        }
    }
}
echo "   pares visitados: $niveis (o quinto dispara o break 3)\n";

// O par break/continue em filtro de entrada.
echo "\n9. Filtro com continue e validacao com break\n";
$entradas = ['ana', '', 'bruno', '0', 'cecilia'];
foreach ($entradas as $entrada) {
    if (trim($entrada) === '') {
        echo "   descartado: campo em branco\n";
        continue;
    }
    if (strlen($entrada) < 3) {
        echo "   descartado: $entrada tem menos de 3 letras\n";
        continue;
    }
    echo "   aceito: $entrada\n";
}

Saída real

1. break interrompe o laco
  processando 1
  processando 2
  processando 3
   break no 4: o 4 e os seguintes nao entram

2. continue pula para a proxima iteracao
   apenas impares: 1
   apenas impares: 3
   apenas impares: 5
   apenas impares: 7

3. continue no fim do corpo equivale a nada, e sautavel
   3
   4
   5
   6
   7
   8

4. break 2 e continue 2 em laco aninhado
   par 1x (o 'y' nao aparece)

5. continue 2 pula a volta do laco de fora
   1 x 1
   2 x 1
   3 x 1

6. break comum em laco aninhado sai so do interno
   volta ao laco externo com a = 1
   volta ao laco externo com a = 2

7. Rotulo com goto para interromper lacos aninhados
   i=1 j=1
   i=1 j=2
   i=1 j=3
   i=2 j=1
   i=2 j=2
   saiu pelo rotulo 'fim'

8. break 3 em tres niveis
   pares visitados: 5 (o quinto dispara o break 3)

9. Filtro com continue e validacao com break
   aceito: ana
   descartado: campo em branco
   aceito: bruno
   descartado: 0 tem menos de 3 letras
   aceito: cecilia