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.
- 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
fordentro de outro. - Gerar as opções de 1 a 31 de um
<select>numa página web. - Usar o
forcom arrays, e quando oforeaché melhor. - As diferenças entre
forewhile, 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:
- Início: começa na volta 1.
- Condição: continua enquanto a volta for no máximo 5.
- 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 | $i | O que acontece |
|---|---|---|
| Início | 1 | $i = 1 (só desta vez) |
| Condição | 1 | 1 <= 5? Sim → roda o corpo: "Volta número 1" |
| Passo | 2 | $i++ |
| Condição | 2 | 2 <= 5? Sim → "Volta número 2" |
| … | … | (o mesmo para 3, 4 e 5) |
| Passo | 6 | $i++ depois da volta 5 |
| Condição | 6 | 6 <= 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ço | Início | Condição | Passo |
|---|---|---|---|
| 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>
| Trecho | O 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.
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ção | Use | Exemplo |
|---|---|---|
| Você sabe quantas vezes vai repetir, ou conta de um número a outro | for | Tabuada, dias de 1 a 31, contagem regressiva |
| Percorrer todos os itens de um array | foreach | Lista de compras, produtos, alunos |
| Repetir enquanto algo for verdade, sem saber quantas vezes | while | Ler um arquivo até o fim, perguntar até a resposta ser válida |
| Executar pelo menos uma vez e depois testar | do-while | Mostrar 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.
<?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 {.
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++).
<?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
| Forma | O 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 / continue | Sair 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:
2. Contagem regressiva
Complete o passo para contar de 10 até 0:
3. De 3 em 3
Complete o passo para mostrar 0, 3, 6, 9, 12:
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, oforeaché melhor. forquando você sabe quantas vezes;whilequando depende de uma condição;foreachpara arrays.