Sua dose diária de programação

Conceito, 3 exemplos e 3 exercícios: uma pequena conquista de cada vez.

✦   Lição

Variáveis e tipos básicos

Em PHP, toda variável começa com $ e passa a existir na primeira atribuição. Não há declaração de tipo: o tipo pertence ao valor guardado, e a mesma variável pode receber um texto agora e um número depois. Por isso se diz que o PHP tem tipagem dinâmica.

PHP Fundamentos Iniciante 3 exemplos + 3 exercícios
42 lições publicadas 10 linguagens novas lições todo dia útil
PHP / Fundamentos

Variáveis e tipos básicos

por Ellery Blackwood
Iniciante

Entenda o conceito

Em PHP, toda variável começa com $ e passa a existir na primeira atribuição. Não há declaração de tipo: o tipo pertence ao valor guardado, e a mesma variável pode receber um texto agora e um número depois. Por isso se diz que o PHP tem tipagem dinâmica.

Os quatro tipos escalares do dia a dia são int (inteiros como 42), float (decimais como 18.9), string (texto entre aspas) e bool (true ou false). Para descobrir o tipo de um valor, use var_dump(), que mostra tipo e conteúdo, ou get_debug_type(), que devolve só o nome do tipo. As funções is_int(), is_string() e parecidas respondem com um bool.

O PHP converte tipos sozinho em muitas operações, e isso pode surpreender: == compara valores depois de converter, enquanto === exige também o mesmo tipo. Quando a conversão é intencional, escreva-a com um cast como (int) ou (float). Em código moderno, declare(strict_types=1) com tipos nos parâmetros das funções faz o PHP recusar valores do tipo errado em vez de adivinhar.

↳ Pontos-chave
  • Variáveis começam com $, nascem na primeira atribuição e não declaram tipo: o tipo vem do valor guardado.
  • Os tipos escalares são int, float, string e bool; var_dump() mostra tipo e valor, e get_debug_type() devolve só o nome do tipo.
  • Casts como (int), (float), (string) e (bool) convertem de forma explícita; (int) 7.9 corta para 7, sem arredondar.
  • Prefira === a ==: o primeiro compara valor e tipo, o segundo converte os valores antes de comparar.
  • Com declare(strict_types=1), passar uma string para um parâmetro int gera TypeError em vez de uma conversão silenciosa.

Do conceito à prática

3 exemplos para ver a ideia funcionando.

01Os quatro tipos escalares no estoque

estoque.php
<?php

// Um produto do estoque descrito com os quatro tipos escalares.
// O tipo vem do valor: não existe declaração como "int x".
$produto = "Caderno universitário"; // string: texto
$quantidade = 42;                   // int: número inteiro
$preco = 18.9;                      // float: número com casas decimais
$emPromocao = false;                // bool: verdadeiro ou falso

// var_dump mostra o tipo e o valor; ótimo para depurar.
var_dump($produto);
var_dump($quantidade);
var_dump($preco);
var_dump($emPromocao);

// A mesma variável pode receber um valor de outro tipo depois.
$quantidade = "esgotado";
var_dump($quantidade);

// Separadores _ deixam números grandes legíveis (o valor não muda).
$unidadesVendidas = 1_250;
var_dump($unidadesVendidas);

Cada variável descreve uma parte do produto e recebe um tipo diferente só pelo valor: aspas geram string, 42 gera int, 18.9 gera float e false gera bool. O var_dump() imprime string(22) "Caderno universitário", int(42), float(18.9) e bool(false). Repare que o 22 é o tamanho em bytes: o ú ocupa dois bytes em UTF-8, embora o texto tenha 21 letras.

A reatribuição de $quantidade com um texto mostra a tipagem dinâmica: o PHP aceita, e o tipo muda para string. Isso é permitido, mas costuma confundir; em código real, mantenha cada variável com um único tipo. O 1_250 mostra o separador de milhares em literais numéricos, que só melhora a leitura.

02Descobrindo e comparando tipos no boletim

boletim.php
<?php

// Dados de um aluno, alguns vindos de um formulário (sempre texto).
$aluno = "Marina";
$faltas = 3;
$notaFinal = 8.5;
$notaDigitada = "8.5"; // o que chegou do formulário
$matriculada = true;

// get_debug_type devolve o nome moderno do tipo (int, float, bool...).
echo "aluno: " . get_debug_type($aluno) . PHP_EOL;
echo "faltas: " . get_debug_type($faltas) . PHP_EOL;
echo "notaFinal: " . get_debug_type($notaFinal) . PHP_EOL;
echo "matriculada: " . get_debug_type($matriculada) . PHP_EOL;

// gettype é a função antiga e usa nomes como "integer" e "double".
echo "gettype(faltas): " . gettype($faltas) . PHP_EOL;
echo "gettype(notaFinal): " . gettype($notaFinal) . PHP_EOL;

// As funções is_* respondem com bool se o valor é de um tipo.
var_dump(is_float($notaDigitada));
var_dump(is_numeric($notaDigitada));

// == compara só o valor (converte antes); === exige o mesmo tipo.
var_dump($notaFinal == $notaDigitada);
var_dump($notaFinal === $notaDigitada);

get_debug_type() devolve os nomes atuais dos tipos (int, float, bool), os mesmos usados nas declarações de função. Já gettype(), mais antiga, responde integer e double; vale reconhecê-la em código legado, mas a primeira é a mais indicada.

A nota digitada é a string "8.5": is_float() diz que ela não é float, e is_numeric() confirma que é um texto que representa número. Na comparação, == converte a string e responde true, enquanto === responde false porque os tipos diferem. Essa é a razão de preferir ===: o resultado não depende de conversões escondidas.

03Casts e tipos estritos na receita

receita.php
<?php

declare(strict_types=1);

// Constante: valor fixo, sem $, que não pode ser reatribuído.
const PORCOES_ORIGINAIS = 4;

// Os tipos nos parâmetros e no retorno documentam e protegem a função.
function escalar(float $quantidade, int $porcoes): float
{
    return $quantidade / PORCOES_ORIGINAIS * $porcoes;
}

// Valores digitados pelo usuário chegam como string.
$porcoesDigitadas = "6";
$farinhaDigitada = "250";

// Casts convertem de forma explícita antes de usar os valores.
$porcoes = (int) $porcoesDigitadas;
$farinha = (float) $farinhaDigitada;

$farinhaAjustada = escalar($farinha, $porcoes);
echo "Farinha para $porcoes porções: $farinhaAjustada g" . PHP_EOL;

// Outros casts comuns e o que eles produzem.
var_dump((int) 7.9);      // corta as casas decimais, não arredonda
var_dump((bool) "0");     // a string "0" é falsa
var_dump((bool) "não");   // qualquer outro texto não vazio é verdadeiro
var_dump((string) 2.50);  // zeros finais desaparecem

// Com strict_types, passar "6" no lugar de um int gera TypeError.
try {
    escalar(250.0, "6");
} catch (TypeError $erro) {
    echo "Erro de tipo: o segundo argumento precisa ser int" . PHP_EOL;
}

A função escalar() declara float e int nos parâmetros e float no retorno. Os valores digitados chegam como string e são convertidos com casts antes da chamada, então a receita de 4 porções vira 375 g de farinha para 6. A constante PORCOES_ORIGINAIS, criada com const, não usa $ e não pode ser alterada.

Os var_dump mostram casts que costumam surpreender: (int) 7.9 corta para 7, (bool) "0" é false e qualquer outro texto não vazio é true, e (string) 2.50 vira "2.5". No fim, a chamada com "6" dispara TypeError por causa do strict_types; sem ele, o PHP converteria o texto em silêncio.


Agora é com você

Tente resolver no rascunho antes de abrir a resposta. Os códigos não são executados nesta página.

01Ficha de item do inventárioFácil

Em um jogo, descreva um item do inventário do jogador com quatro variáveis (nome, quantidade, peso e se está equipado) e imprima cada valor seguido do nome do seu tipo entre parênteses.

↳ Requisitos
  • Usar um tipo escalar diferente em cada variável: string, int, float e bool.
  • Obter o nome do tipo com get_debug_type(), sem escrever os nomes dos tipos à mão.
  • Mostrar o bool como sim ou não, mantendo a variável original como bool.
  • Imprimir exatamente as linhas da saída esperada.
código inicial
<?php

$item = "Espada curta";
$quantidade = 3;
$peso = 2.5;
$equipado = true;

// Imprima cada valor e o tipo dele entre parênteses.
saída esperada
Item: Espada curta (string)
Quantidade: 3 (int)
Peso: 2.5 (float)
Equipado: sim (bool)
Ver dica

O PHP não executa funções dentro das aspas: feche o texto, concatene a chamada de função com o ponto e reabra.

Ver resposta
<?php

// Um item do inventário do jogador, um tipo escalar por variável.
$item = "Espada curta";
$quantidade = 3;
$peso = 2.5;
$equipado = true;

// O operador ternário transforma o bool em texto legível.
$equipadoTexto = $equipado ? "sim" : "não";

// get_debug_type informa o tipo de cada variável.
echo "Item: $item (" . get_debug_type($item) . ")" . PHP_EOL;
echo "Quantidade: $quantidade (" . get_debug_type($quantidade) . ")" . PHP_EOL;
echo "Peso: $peso (" . get_debug_type($peso) . ")" . PHP_EOL;
echo "Equipado: $equipadoTexto (" . get_debug_type($equipado) . ")" . PHP_EOL;

Passo a passo

  1. Cada variável recebe um valor de um tipo escalar diferente: texto entre aspas vira string, 3 vira int, 2.5 vira float e true vira bool.
  2. Nenhuma variável declara o tipo: o PHP o descobre pelo valor no momento da atribuição.
  3. O ternário $equipado ? "sim" : "não" escolhe um texto conforme o bool, porque imprimir true direto mostraria só 1.
  4. Em cada linha, a interpolação coloca o valor no texto e get_debug_type() devolve o nome do tipo.
  5. A chamada de função fica fora das aspas e entra com o ponto, porque o PHP não interpola funções dentro do texto.
  6. Todas as linhas terminam com PHP_EOL, inclusive a última.

Por que funciona

O tipo de uma variável em PHP pertence ao valor que ela guarda naquele momento. Por isso get_debug_type() consegue responder string, int, float ou bool sem nenhuma declaração prévia: ele só olha o valor atual.

O bool merece cuidado na exibição: convertido em texto, true vira "1" e false vira "". Traduzir com o ternário deixa a saída legível sem mudar o tipo da variável original, que continua bool.

Erros comuns

  • Escrever o número entre aspas: $quantidade = "3"; imprime Quantidade: 3 (string). Números sem aspas viram int ou float.
  • Imprimir o bool direto: echo "Equipado: $equipado"; mostra Equipado: 1, e com false mostraria nada. Converta para texto com o ternário.
  • Usar gettype() no lugar: ele devolve integer e double, nomes antigos que não batem com a saída esperada. Use get_debug_type().
  • Colocar a função dentro das aspas: "($quantidade get_debug_type($quantidade))" imprime o nome da função como texto. Feche as aspas e concatene.

Outra forma de resolver

printf("Peso: %s (%s)\n", $peso, get_debug_type($peso)); monta cada linha com marcadores e evita a mistura de interpolação e concatenação. É preferível quando há muitas linhas no mesmo formato, porque o desenho da linha fica num lugar só.

Saída esperada

Item: Espada curta (string)
Quantidade: 3 (int)
Peso: 2.5 (float)
Equipado: sim (bool)

02Média do boletim a partir de textoMédio

Três notas de um aluno chegaram de um formulário como texto. Converta-as para número, calcule a média, mostre-a com duas casas, informe o tipo do resultado e diga se o aluno foi aprovado (média maior ou igual a 7).

↳ Requisitos
  • Converter as notas com o cast (float) antes de somar.
  • Mostrar a média com duas casas usando number_format(), sem alterar o valor guardado em $media.
  • Guardar a aprovação em uma variável bool e imprimi-la como true ou false com var_export().
  • Imprimir exatamente as quatro linhas da saída esperada.
código inicial
<?php

$nota1 = "7.5";
$nota2 = "8";
$nota3 = "6.5";

// 1. Converta as notas e calcule a média.
// 2. Descubra se o aluno foi aprovado.
// 3. Imprima as quatro linhas.
saída esperada
Notas: 7.5, 8, 6.5
Média: 7.33
Tipo da média: float
Aprovado: true
Ver dica

var_export() imprime na hora, a menos que você passe um segundo argumento que o faz devolver o texto.

Ver resposta
<?php

// Notas como chegam de um formulário: sempre texto.
$nota1 = "7.5";
$nota2 = "8";
$nota3 = "6.5";

// Cast explícito para float antes de fazer contas.
$soma = (float) $nota1 + (float) $nota2 + (float) $nota3;
$media = $soma / 3;

// Comparação gera um bool.
$aprovado = $media >= 7;

echo "Notas: $nota1, $nota2, $nota3" . PHP_EOL;
// number_format arredonda para 2 casas só na exibição.
echo "Média: " . number_format($media, 2) . PHP_EOL;
echo "Tipo da média: " . get_debug_type($media) . PHP_EOL;
// var_export com true devolve "true" ou "false" como texto.
echo "Aprovado: " . var_export($aprovado, true) . PHP_EOL;

Passo a passo

  1. As três notas são strings, como qualquer dado que chega de um formulário ou da linha de comando.
  2. (float) $nota1 converte o texto em número de forma explícita; a soma passa a trabalhar só com floats.
  3. A média é a soma dividida por 3; o resultado é 7.333..., um float.
  4. $media >= 7 é uma comparação, e toda comparação produz um bool.
  5. A primeira linha interpola as strings originais, por isso 8 aparece sem casas decimais.
  6. number_format($media, 2) arredonda para duas casas só na hora de mostrar; $media continua com todas as casas.
  7. var_export($aprovado, true) devolve o texto true, em vez do 1 que o echo mostraria.

Por que funciona

O PHP até converteria "7.5" + "8" sozinho, mas o cast deixa a intenção clara para quem lê e garante o tipo antes da conta. Assim a soma e a divisão acontecem entre floats, e get_debug_type() confirma que a média é float.

Separar o valor calculado da sua apresentação também é importante: a variável guarda a média exata e só a exibição é arredondada. Se a média fosse usada em outra conta, nada se perderia.

Erros comuns

  • Converter para int: (int) $nota1 transforma "7.5" em 7 e "6.5" em 6, e a média vira 7.00. Notas com decimais pedem (float).
  • Arredondar a variável cedo demais: $media = round($soma / 3, 2); funciona aqui, mas descarta casas que podem fazer falta depois. Arredonde só na saída.
  • Imprimir o bool com echo: echo "Aprovado: $aprovado"; mostra Aprovado: 1. Use var_export($aprovado, true).
  • Esquecer o segundo argumento: var_export($aprovado) imprime na hora e devolve null, então o texto sai antes de Aprovado: . Passe true para receber o texto.

Outra forma de resolver

floatval($nota1) faz o mesmo que (float) $nota1 e pode ser passado como callback, por exemplo em array_map('floatval', $notas), quando as notas estão num array. Para três variáveis soltas, o cast é mais curto e direto.

Saída esperada

Notas: 7.5, 8, 6.5
Média: 7.33
Tipo da média: float
Aprovado: true

03Carrinho em centavosDesafio

Os preços e as quantidades de um carrinho chegaram como texto. Converta os preços para centavos inteiros, calcule os subtotais e o total só com inteiros e imprima os valores no formato brasileiro.

↳ Requisitos
  • Ativar declare(strict_types=1) e criar paraCentavos(string $preco): int e emReais(int $centavos): string.
  • Arredondar com round() antes do cast para int ao converter o preço em centavos.
  • Calcular subtotais e total com inteiros, sem escrever os números 5630 ou 56.30 no código.
  • Mostrar o tipo do total com get_debug_type() e reproduzir exatamente a saída esperada.
código inicial
<?php

declare(strict_types=1);

$produto1 = "Camiseta";
$preco1 = "19.90";
$quantidade1 = "2";
$produto2 = "Meia";
$preco2 = "5.50";
$quantidade2 = "3";

// 1. Crie paraCentavos() e emReais().
// 2. Calcule subtotais e total em centavos.
// 3. Imprima as quatro linhas.
saída esperada
Camiseta: 2 x R$ 19,90 = R$ 39,80
Meia: 3 x R$ 5,50 = R$ 16,50
Total em centavos: 5630 (int)
Total: R$ 56,30
Ver dica

Teste var_dump(19.9 * 100); antes de escrever o cast: o resultado mostra por que o arredondamento é necessário.

Ver resposta
<?php

declare(strict_types=1);

// Recebe centavos (int) e devolve o texto no formato brasileiro.
function emReais(int $centavos): string
{
    return "R$ " . number_format($centavos / 100, 2, ",", ".");
}

// Converte um preço em texto ("19.90") para centavos inteiros.
function paraCentavos(string $preco): int
{
    return (int) round((float) $preco * 100);
}

// Dados do carrinho como vieram do formulário: tudo string.
$produto1 = "Camiseta";
$preco1 = "19.90";
$quantidade1 = "2";
$produto2 = "Meia";
$preco2 = "5.50";
$quantidade2 = "3";

// Preços em centavos e quantidades convertidos para int.
$unitario1 = paraCentavos($preco1);
$unitario2 = paraCentavos($preco2);
$subtotal1 = $unitario1 * (int) $quantidade1;
$subtotal2 = $unitario2 * (int) $quantidade2;
$total = $subtotal1 + $subtotal2;

echo "$produto1: $quantidade1 x " . emReais($unitario1) . " = " . emReais($subtotal1) . PHP_EOL;
echo "$produto2: $quantidade2 x " . emReais($unitario2) . " = " . emReais($subtotal2) . PHP_EOL;
echo "Total em centavos: $total (" . get_debug_type($total) . ")" . PHP_EOL;
echo "Total: " . emReais($total) . PHP_EOL;

Passo a passo

  1. declare(strict_types=1) faz o PHP recusar argumentos do tipo errado nas funções, em vez de convertê-los em silêncio.
  2. emReais(int $centavos): string recebe um inteiro e devolve texto; dividir por 100 só acontece na exibição.
  3. number_format(..., 2, ",", ".") usa vírgula nos decimais e ponto nos milhares, o formato brasileiro.
  4. paraCentavos() converte a string em float, multiplica por 100 e usa round() antes do cast para int.
  5. As quantidades chegam como texto e viram int com (int) antes da multiplicação.
  6. Subtotais e total são somas de inteiros, então não há erro de arredondamento acumulado.
  7. A linha do total em centavos usa get_debug_type() para provar que o resultado é int.

Por que funciona

Floats guardam valores em binário, e números como 19.90 não têm representação exata: 19.9 * 100 dá 1989.9999999999998. O round() corrige esse resíduo, e o cast para int produz 1990 exato. A partir daí, todas as contas são entre inteiros, que o computador representa sem perda.

Os tipos nas assinaturas das funções reforçam a regra: com strict_types, passar a string "1990" para emReais() gera TypeError. O erro aparece cedo, no ponto exato da chamada, em vez de virar um valor errado lá na frente.

Erros comuns

  • Fazer o cast sem arredondar: (int) ((float) "19.90" * 100) dá 1989, porque o cast corta as casas de 1989.999.... Arredonde com round() antes.
  • Somar os preços como float: 19.9 * 2 + 5.5 * 3 funciona neste caso, mas em carrinhos maiores os resíduos se acumulam e a comparação com um valor esperado falha. Some centavos inteiros.
  • Esquecer de converter a quantidade: com strict_types a multiplicação $unitario1 * $quantidade1 ainda funciona (operadores não são afetados), mas passar $quantidade1 para uma função com parâmetro int gera TypeError. Converta logo na entrada.
  • Usar number_format($centavos / 100, 2) sem os separadores: o resultado é 56.30, no formato americano. Informe "," e ".".

Outra forma de resolver

intdiv($total, 100) e $total % 100 separam reais e centavos sem passar por float, e sprintf("R$ %d,%02d", ...) monta o texto. Essa forma é preferível quando se quer evitar float até na exibição, mas não insere o ponto dos milhares; para valores grandes, number_format é mais prático.

Saída esperada

Camiseta: 2 x R$ 19,90 = R$ 39,80
Meia: 3 x R$ 5,50 = R$ 16,50
Total em centavos: 5630 (int)
Total: R$ 56,30

Últimas lições

Ver o arquivo completo →