PHP for

O for ("para") é o laço de contar: de 1 até 10, de 10 até 1, de 5 em 5. Ele junta numa única linha as três coisas que todo contador precisa: onde começa, até onde vai e de quanto em quanto anda. Por isso é o laço preferido quando você sabe quantas vezes quer repetir.

Você vai aprender
  • A anatomia do for: início, condição e passo, e em que ordem cada um roda.
  • Contar para frente, para trás e pulando números.
  • Fazer a tabuada e uma tabela com um for dentro de outro.
  • Gerar as opções de 1 a 31 de um <select> numa página web.
  • Usar o for com arrays, e quando o foreach é melhor.
  • As diferenças entre for e while, e os erros mais comuns.

Esta aula vem depois de while e do-while; se você já leu, vai perceber que o for é um while "organizado". Os exemplos rodam na pasta ~/site da Ana.


A ideia antes do código: as voltas na pista

A Ana decidiu correr 5 voltas na pista do parque. Antes de começar, ela já sabe três coisas:

  1. Início: começa na volta 1.
  2. Condição: continua enquanto a volta for no máximo 5.
  3. Passo: a cada volta completada, soma 1 no contador.

Com essas três informações, qualquer pessoa sabe exatamente quantas vezes ela vai correr. O for pede essas mesmas três coisas, nessa ordem, separadas por ponto e vírgula.


Anatomia do for

<?php
for ($i = 1; $i <= 5; $i++) {
    echo "Volta número $i\n";
}
echo "Depois do laço, \$i vale $i\n";
for
"Para". Começa o laço.
$i = 1;
Início: cria o contador. Roda uma vez só, antes de tudo. O nome $i (de "índice") é uma tradição; pode ser $volta, $dia, o que fizer sentido.
$i <= 5;
Condição: testada antes de cada volta. Se for verdadeira, o corpo roda; se for falsa, o laço acaba.
$i++
Passo: roda depois de cada volta. $i++ soma 1 (veja Operadores de Atribuição). Repare: depois do passo não vai ponto e vírgula.
{ … }
O corpo, repetido a cada volta.
$ php contar.php
Volta número 1
Volta número 2
Volta número 3
Volta número 4
Volta número 5
Depois do laço, $i vale 6

A ordem exata das coisas

É aqui que muita gente se confunde, então vale seguir volta por volta:

Passo$iO que acontece
Início1$i = 1 (só desta vez)
Condição11 <= 5? Sim → roda o corpo: "Volta número 1"
Passo2$i++
Condição22 <= 5? Sim → "Volta número 2"
……(o mesmo para 3, 4 e 5)
Passo6$i++ depois da volta 5
Condição66 <= 5? Não → o laço termina

Por isso, depois do laço, $i vale 6, e não 5: foi o 6 que fez a condição falhar. E, como if e laços não criam escopo em PHP, o $i continua existindo depois do laço (veja Escopo).

Experimente: mude o 5 para 3; depois troque o <= por < e veja que sai uma volta a menos. Por fim, comece com $i = 0: quantas voltas saem agora?

<?php
for ($i = 1; $i <= 5; $i++) {
    echo "Volta número $i\n";
}
echo "Depois do laço, \$i vale $i\n";

Contar de outros jeitos

Mudando o início, a condição e o passo, o mesmo for conta de qualquer jeito:

<?php
for ($i = 10; $i >= 1; $i--) {
    echo $i, " ";
}
echo "Feliz Ano Novo!\n";

for ($i = 0; $i <= 20; $i += 5) {
    echo $i, " ";
}
echo "\n";

for ($i = 2; $i <= 10; $i += 2) {
    echo $i, " ";
}
echo "\n";
LaçoInícioCondiçãoPasso
Contagem regressiva$i = 10$i >= 1 ("maior ou igual")$i-- (diminui 1)
De 5 em 5$i = 0$i <= 20$i += 5 (soma 5)
Só os pares$i = 2$i <= 10$i += 2
$ php variacoes.php
10 9 8 7 6 5 4 3 2 1 Feliz Ano Novo!
0 5 10 15 20
2 4 6 8 10 

Quando conta para trás, tudo vira ao contrário: a condição usa >= e o passo diminui. Esquecer de inverter um dos dois é um erro clássico (veja Quando dá errado).


A tabuada

O contador não serve só para ser mostrado: ele pode entrar em contas. A tabuada do 7:

<?php
$numero = 7;

for ($i = 1; $i <= 10; $i++) {
    $resultado = $numero * $i;
    echo "$numero x $i = $resultado\n";
}
$ php tabuada.php
7 x 1 = 7
7 x 2 = 14
7 x 3 = 21
7 x 4 = 28
7 x 5 = 35
7 x 6 = 42
7 x 7 = 49
7 x 8 = 56
7 x 9 = 63
7 x 10 = 70

Para ter a tabuada de outro número, basta mudar $numero. E se você quiser várias tabuadas de uma vez?

Um for dentro de outro: a tabela de multiplicação

Colocando um laço dentro de outro, o de dentro roda inteiro a cada volta do de fora. É assim que se percorre uma tabela: o de fora anda pelas linhas, o de dentro pelas colunas.

<?php
for ($linha = 1; $linha <= 5; $linha++) {
    for ($coluna = 1; $coluna <= 5; $coluna++) {
        echo str_pad($linha * $coluna, 4, " ", STR_PAD_LEFT);
    }
    echo "\n";
}
for ($linha = 1; …)
O laço de fora: 5 voltas, uma por linha.
for ($coluna = 1; …)
O laço de dentro: a cada linha, 5 voltas, uma por coluna. No total, 5 × 5 = 25 contas. Os dois contadores precisam ter nomes diferentes.
str_pad(…, 4, " ", STR_PAD_LEFT)
Completa o número com espaços à esquerda até ter 4 caracteres, para as colunas ficarem alinhadas (veja Funções de String).
echo "\n";
Fica no laço de fora, depois do de dentro: pula a linha quando as 5 colunas terminam.
$ php tabela.php
   1   2   3   4   5
   2   4   6   8  10
   3   6   9  12  15
   4   8  12  16  20
   5  10  15  20  25

Na página web: as opções de 1 a 31

Um uso muito comum do for em sites: gerar listas de números para formulários. A Ana quer perguntar o dia do aniversário dos clientes com um <select>. Escrever 31 linhas de <option> à mão seria cansativo; o for escreve por ela. Dentro do HTML, use a forma alternativa for (…): … endfor; (a mesma ideia do endforeach, explicada em foreach):

Missão: a página abriu como se alguém tivesse escolhido o dia 15. Abra a lista na aba Resultado: o dia 31 está faltando! Corrija a condição do for para as opções irem de 1 até 31. Depois escolha um dia e clique em Enviar.

<?php
$dia = isset($_GET["dia"]) ? (int) $_GET["dia"] : null;
?>
<!doctype html>
<html lang="pt-BR">
<head><meta charset="utf-8"><title>Aniversário</title></head>
<body>
<form method="get">
  <label>Dia do seu aniversário:
    <select name="dia">
<?php for ($d = 1; $d < 31; $d++): ?>
      <option value="<?= $d ?>"><?= $d ?></option>
<?php endfor; ?>
    </select>
  </label>
  <button>Enviar</button>
</form>
<?php if ($dia !== null): ?>
<p>Você faz aniversário no dia <?= $dia ?>.</p>
<?php endif; ?>
</body>
</html>
<?php
$dia = isset($_GET["dia"]) ? (int) $_GET["dia"] : null;
?>
<!doctype html>
<html lang="pt-BR">
<head><meta charset="utf-8"><title>Aniversário</title></head>
<body>
<form method="get">
  <label>Dia do seu aniversário:
    <select name="dia">
<?php for ($d = 1; $d <= 31; $d++): ?>
      <option value="<?= $d ?>"><?= $d ?></option>
<?php endfor; ?>
    </select>
  </label>
  <button>Enviar</button>
</form>
<?php if ($dia !== null): ?>
<p>Você faz aniversário no dia <?= $dia ?>.</p>
<?php endif; ?>
</body>
</html>
TrechoO que faz
$_GET["dia"]O dia escolhido, que chega pelo endereço (?dia=15) quando o formulário é enviado (veja $_GET e $_POST).
(int)Transforma o que chegou em número inteiro. Além de converter, isso protege a página: qualquer texto estranho vira um número, e número não tem como esconder HTML malicioso (veja Conversão de Tipos).
<?php for (…): ?> … <?php endfor; ?>O HTML entre os dois é repetido a cada volta, com o $d da vez.
value="<?= $d ?>"O valor enviado pelo formulário. O texto entre > e </option> é o que o usuário vê.

Com o servidor embutido, a Ana conferiu o HTML que o PHP gera (com ?dia=15 no endereço, como se o formulário tivesse sido enviado):

$ curl -s "localhost:8000/aniversario.php?dia=15" | head -14
<!doctype html>
<html lang="pt-BR">
<head><meta charset="utf-8"><title>Aniversário</title></head>
<body>
<form method="get">
  <label>Dia do seu aniversário:
    <select name="dia">
      <option value="1">1</option>
      <option value="2">2</option>
      <option value="3">3</option>
      <option value="4">4</option>
      <option value="5">5</option>
      <option value="6">6</option>
      <option value="7">7</option>
$ curl -s "localhost:8000/aniversario.php?dia=15" | tail -6
  </label>
  <button>Enviar</button>
</form>
<p>Você faz aniversário no dia 15.</p>
</body>
</html>

O mesmo truque serve para os meses (1 a 12), os anos (for ($a = 2026; $a >= 1920; $a--), do mais recente para o mais antigo) ou as quantidades de um produto no carrinho.


for com arrays

Como os índices de um array comum são 0, 1, 2…, um for pode percorrê-lo contando de 0 até o tamanho menos 1. O tamanho vem de count() ("contar"):

<?php
$compras = ["pão", "leite", "café"];

for ($i = 0; $i < count($compras); $i++) {
    echo "$i: $compras[$i]\n";
}
$ php array-for.php
0: pão
1: leite
2: café

Repare na condição: $i < count($compras), com menor, não "menor ou igual". O array tem 3 itens, mas o último índice é 2. Usar <= é o erro mais comum com for em arrays.

Para percorrer um array, prefira o foreach

O for só funciona em arrays com índices 0, 1, 2… sem buracos. O foreach funciona com qualquer array (inclusive os associativos, com nomes), não precisa de count e não tem como errar o último índice. Use o for com arrays quando precisar de algo que só o contador dá, como andar de 2 em 2 posições ou comparar cada item com o seguinte ($a[$i] e $a[$i + 1]).


Detalhes do for

Mais de uma variável: vírgulas dentro das partes

Dentro de cada parte, você pode separar várias expressões com vírgula. Aqui, uma variável sobe enquanto a outra desce, até se cruzarem:

<?php
for ($i = 0, $j = 10; $i < $j; $i += 3, $j -= 3) {
    echo "i = $i, j = $j\n";
}
$ php virgulas2.php
i = 0, j = 10
i = 3, j = 7

Na terceira volta, $i seria 6 e $j seria 4: a condição 6 < 4 falha. As vírgulas separam expressões dentro de uma parte; os pontos e vírgulas separam as partes.

Partes vazias

As três partes são opcionais. for (; $i <= 5; ) é igual a um while ($i <= 5), e for (;;), sem nada, repete para sempre (como while (true)), dependendo de um break para sair (veja break e continue). Existem, mas deixam o código mais difícil de ler: se você precisa deles, provavelmente um while fica mais claro.


for × while

Todo for pode ser escrito como while. A mesma contagem de 1 a 5, nos dois:

<?php
// com for: as três partes juntas, numa linha
for ($i = 1; $i <= 5; $i++) {
    echo $i, " ";
}

// com while: as mesmas três partes, espalhadas
$i = 1;                 // início
while ($i <= 5) {       // condição
    echo $i, " ";
    $i++;               // passo
}

Os dois mostram 1 2 3 4 5. A diferença é organização: no for, quem lê vê de uma vez quantas voltas o laço dá. No while, o passo fica lá embaixo, e é fácil esquecê-lo (e criar um laço infinito).

SituaçãoUseExemplo
Você sabe quantas vezes vai repetir, ou conta de um número a outroforTabuada, dias de 1 a 31, contagem regressiva
Percorrer todos os itens de um arrayforeachLista de compras, produtos, alunos
Repetir enquanto algo for verdade, sem saber quantas vezeswhileLer um arquivo até o fim, perguntar até a resposta ser válida
Executar pelo menos uma vez e depois testardo-whileMostrar um menu e repetir enquanto a opção não for "sair"

Quando dá errado

Warning: Undefined array key 3: uma volta a mais
<?php
$compras = ["pão", "leite", "café"];

for ($i = 0; $i <= count($compras); $i++) {
    echo "$i: $compras[$i]\n";
}
$ php fora-limite.php
0: pão
1: leite
2: café

Warning: Undefined array key 3 in /home/ana/site/fora-limite.php on line 5
3: 

O que significa: "chave 3 do array indefinida". O array tem 3 itens (índices 0, 1, 2); com <=, o laço tentou a posição 3, que não existe. Esse erro de "um a mais" (ou "um a menos") é tão comum que tem nome em inglês: off-by-one.

Como consertar: com índices que começam em 0, use $i < count($array). Ou use foreach, que não tem esse problema.

O corpo rodou uma vez só, com o valor final (ponto e vírgula a mais)
<?php
for ($i = 1; $i <= 3; $i++);
{
    echo "Volta $i\n";
}
$ php pontovirgula.php
Volta 4

O que aconteceu: o ; logo depois do ) é um corpo vazio. O laço contou de 1 a 4 sem fazer nada; depois, o bloco { … } rodou uma vez, como código comum, com $i valendo 4. Não há aviso: para o PHP, é código válido.

Como consertar: nunca ponha ; entre o ) do for e a {.

Vírgulas no lugar dos pontos e vírgulas: unexpected token ")", expecting ";"
<?php
for ($i = 1, $i <= 3, $i++) {
    echo "Volta $i\n";
}
$ php virgulas.php

Parse error: syntax error, unexpected token ")", expecting ";" in /home/ana/site/virgulas.php on line 2

O que significa: o PHP leu tudo como a parte do início (vírgulas separam expressões dentro de uma parte) e, ao chegar no ), ainda esperava o ; que separa o início da condição.

Como consertar: as três partes são separadas por ponto e vírgula: for ($i = 1; $i <= 3; $i++).

O laço não para: o passo anda para o lado errado
<?php
for ($i = 10; $i >= 1; $i++) {
    echo $i, "\n";
}
$ php errado.php | head -5
10
11
12
13
14                     « e continuaria para sempre: o head parou o programa na 5ª linha

O que aconteceu: a intenção era contar de 10 até 1, mas o passo é $i++ (sobe). Como $i só cresce, $i >= 1 é sempre verdade. O | head -5 mostra só as 5 primeiras linhas e encerra o programa; sem ele, a tela encheria de números até você apertar Ctrl+C.

Como consertar: confira se o passo leva o contador na direção que faz a condição ficar falsa: contando para baixo, $i--. Mais sobre laços infinitos em while e do-while.


Referência

FormaO que faz
for (início; condição; passo) { … }Início roda uma vez; condição antes de cada volta; passo depois de cada volta.
for ($i = 1; $i <= 10; $i++)De 1 a 10.
for ($i = 10; $i >= 1; $i--)De 10 a 1.
for ($i = 0; $i <= 100; $i += 5)De 0 a 100, de 5 em 5.
for ($i = 0; $i < count($a); $i++)Todas as posições de um array 0, 1, 2… (prefira foreach).
for ($i = 0, $j = 10; …; $i++, $j--)Várias expressões numa parte, separadas por vírgula.
for (…): … endfor;Sintaxe alternativa, para templates HTML.
break / continueSair do laço / pular para a próxima volta (veja break e continue).

Exercícios

1. De 1 a 100

Complete para contar de 1 até 100:

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

2. Contagem regressiva

Complete o passo para contar de 10 até 0:

for ($i = 10; $i >= 0; ) { echo $i; }

3. De 3 em 3

Complete o passo para mostrar 0, 3, 6, 9, 12:

for ($i = 0; $i <= 12; ) { echo $i; }

4. Quantas vezes o corpo de for ($i = 0; $i < 5; $i++) roda?

5. Quanto vale $i depois de for ($i = 1; $i <= 3; $i++) { }?

6. Em que ordem as partes do for rodam a cada volta (depois do início)?

Missão final

Missão: escreva um for que mostre a tabuada do 9 de trás para frente: começando em 9 x 10 = 90 e terminando em 9 x 1 = 9, uma conta por linha.

<?php
$numero = 9;

// escreva o for aqui
<?php
$numero = 9;

for ($i = 10; $i >= 1; $i--) {
    echo "$numero x $i = ", $numero * $i, "\n";
}

Resumo

  • for (início; condição; passo): o início roda uma vez; a condição é testada antes de cada volta; o passo roda depois de cada volta.
  • Para contar para trás, inverta a condição (>=) e o passo ($i--). Para pular, use $i += N.
  • Laços dentro de laços percorrem tabelas; cada um com o seu contador.
  • No HTML, for (…): … endfor; gera listas como as opções de 1 a 31 de um <select>.
  • Em arrays, $i < count($a) (nunca <=); mas, para percorrer arrays, o foreach é melhor.
  • for quando você sabe quantas vezes; while quando depende de uma condição; foreach para arrays.