Variáveis e tipos básicos
por Ellery BlackwoodEntenda 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.
- 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,stringebool;var_dump()mostra tipo e valor, eget_debug_type()devolve só o nome do tipo. - Casts como
(int),(float),(string)e(bool)convertem de forma explícita;(int) 7.9corta para7, 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âmetrointgeraTypeErrorem vez de uma conversão silenciosa.
Do conceito à prática
3 exemplos para ver a ideia funcionando.
01Os quatro tipos escalares no estoque
<?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
<?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
<?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.
- Usar um tipo escalar diferente em cada variável:
string,int,floatebool. - Obter o nome do tipo com
get_debug_type(), sem escrever os nomes dos tipos à mão. - Mostrar o bool como
simounão, mantendo a variável original comobool. - Imprimir exatamente as linhas da saída esperada.
<?php
$item = "Espada curta";
$quantidade = 3;
$peso = 2.5;
$equipado = true;
// Imprima cada valor e o tipo dele entre parênteses.
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
- Cada variável recebe um valor de um tipo escalar diferente: texto entre aspas vira
string,3viraint,2.5virafloatetruevirabool. - Nenhuma variável declara o tipo: o PHP o descobre pelo valor no momento da atribuição.
- O ternário
$equipado ? "sim" : "não"escolhe um texto conforme o bool, porque imprimirtruedireto mostraria só1. - Em cada linha, a interpolação coloca o valor no texto e
get_debug_type()devolve o nome do tipo. - 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.
- 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";imprimeQuantidade: 3 (string). Números sem aspas viramintoufloat. - Imprimir o bool direto:
echo "Equipado: $equipado";mostraEquipado: 1, e comfalsemostraria nada. Converta para texto com o ternário. - Usar
gettype()no lugar: ele devolveintegeredouble, nomes antigos que não batem com a saída esperada. Useget_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).
- 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
boole imprimi-la comotrueoufalsecomvar_export(). - Imprimir exatamente as quatro linhas da saída esperada.
<?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.
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
- As três notas são strings, como qualquer dado que chega de um formulário ou da linha de comando.
(float) $nota1converte o texto em número de forma explícita; a soma passa a trabalhar só com floats.- A média é a soma dividida por 3; o resultado é
7.333..., umfloat. $media >= 7é uma comparação, e toda comparação produz umbool.- A primeira linha interpola as strings originais, por isso
8aparece sem casas decimais. number_format($media, 2)arredonda para duas casas só na hora de mostrar;$mediacontinua com todas as casas.var_export($aprovado, true)devolve o textotrue, em vez do1que oechomostraria.
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) $nota1transforma"7.5"em7e"6.5"em6, e a média vira7.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";mostraAprovado: 1. Usevar_export($aprovado, true). - Esquecer o segundo argumento:
var_export($aprovado)imprime na hora e devolvenull, então o texto sai antes deAprovado:. Passetruepara 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.
- Ativar
declare(strict_types=1)e criarparaCentavos(string $preco): inteemReais(int $centavos): string. - Arredondar com
round()antes do cast paraintao converter o preço em centavos. - Calcular subtotais e total com inteiros, sem escrever os números
5630ou56.30no código. - Mostrar o tipo do total com
get_debug_type()e reproduzir exatamente a saída esperada.
<?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.
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
declare(strict_types=1)faz o PHP recusar argumentos do tipo errado nas funções, em vez de convertê-los em silêncio.emReais(int $centavos): stringrecebe um inteiro e devolve texto; dividir por 100 só acontece na exibição.number_format(..., 2, ",", ".")usa vírgula nos decimais e ponto nos milhares, o formato brasileiro.paraCentavos()converte a string emfloat, multiplica por 100 e usaround()antes do cast paraint.- As quantidades chegam como texto e viram
intcom(int)antes da multiplicação. - Subtotais e total são somas de inteiros, então não há erro de arredondamento acumulado.
- 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 de1989.999.... Arredonde comround()antes. - Somar os preços como float:
19.9 * 2 + 5.5 * 3funciona 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_typesa multiplicação$unitario1 * $quantidade1ainda funciona (operadores não são afetados), mas passar$quantidade1para uma função com parâmetrointgeraTypeError. 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