PHP Conversão de Tipos
Um formulário pergunta a idade da cliente, ela digita 29, e o PHP recebe… a string "29". Tudo o que vem da web chega como texto. Para fazer contas, o texto precisa virar número; para mostrar um número, ele precisa virar texto. Essa troca de tipo se chama conversão. Às vezes o PHP faz sozinho (e às vezes faz o que você não queria); às vezes você pede. Nesta aula você aprende as duas formas, vê o que acontece com textos que quase são números e conhece a chave que liga o "modo rigoroso" do PHP.
- Como o PHP converte os tipos sozinho (type juggling) em contas, textos e decisões.
- O que acontece com
"10" + 5,"10 maçãs" + 5e"abc" + 1no PHP 8. - Como converter você mesmo:
(int),(float),(string),(bool). - As funções
intval,floatval,strval,boolvalesettype. - O que é
declare(strict_types=1), só para reconhecê-lo.
Os programas desta aula rodaram com o PHP 8.5 na máquina fictícia da Ana, na pasta ~/site. Você já conhece os tipos (Tipos de Dados) e o var_dump (var_dump e print_r), que vamos usar o tempo todo.
A ideia: o tradutor automático e o tradutor contratado
Imagine uma loja com clientes estrangeiros. Há duas formas de entender o que eles dizem:
- Um tradutor automático, que traduz sozinho sempre que acha necessário. É rápido, mas às vezes traduz errado sem avisar.
- Um tradutor contratado, a quem você pede explicitamente: "traduza isto para português". Dá mais trabalho, mas você sabe exatamente o que foi feito.
O PHP tem os dois. A conversão automática (chamada type juggling, "malabarismo de tipos") acontece sozinha quando o PHP precisa de um tipo e recebe outro. A conversão explícita (o casting) é quando você escreve no código "converta para inteiro".
1. A conversão automática
O PHP olha o operador para decidir o tipo de que precisa. O + precisa de números; o ponto (.) precisa de texto; o if precisa de booleano. Se recebe outro tipo, converte:
<?php
var_dump("10" + 5);
var_dump("10" . 5);
var_dump("1.5" + 1);
var_dump(" 10" + 5);
var_dump("1e2" + 0);
var_dump(true + 1);
var_dump(null + 1);
var_dump("10" * "2");
$ php automatica.php int(15) « "10" virou o número 10 para a soma string(3) "105" « o ponto quer texto: o 5 virou "5" e foi colado float(2.5) « "1.5" virou float int(15) « espaços no começo (e no fim) são tolerados float(100) « "1e2" é notação científica: 100.0 int(2) « true vale 1 int(1) « null vale 0 int(20) « os dois textos viraram números
| Onde | O PHP precisa de | Exemplo | Resultado |
|---|---|---|---|
+ - * / % ** | número | "10" + 5 | 15 |
. e echo | texto | "10" . 5 | "105" |
if, while, !, && | booleano | if ("0") | falso (aula Booleanos) |
==, <, > | tipos "compatíveis" | 10 == "10" | true (aula Comparação) |
Repare na diferença das duas primeiras linhas: o mesmo par "10" e 5 deu 15 com + e "105" com .. Em PHP, o operador decide. (Em JavaScript, "10" + 5 dá "105"; o PHP evita essa confusão tendo um operador separado para juntar texto, o ponto.)
2. Texto que é número, que quase é, e que não é
Para fazer conta com uma string, o PHP classifica o texto em três grupos. Cada grupo tem um comportamento diferente no PHP 8:
| Grupo | Exemplos | Numa conta |
|---|---|---|
| Numérico: só um número (espaços nas pontas são aceitos) | "10", " 10", "1.5", "1e2", "-3" | Vira o número, sem aviso. |
| Começa com número: número seguido de outra coisa | "10 maçãs", "12abc", "12,90" | Usa o número do começo e dá Warning. |
| Não numérico | "abc", "maçã", "" | TypeError: o programa para. |
<?php
var_dump("10 maçãs" + 5);
echo "--\n";
var_dump("abc" + 1);
echo "fim\n";
$ php macas.php
Warning: A non-numeric value encountered in /home/ana/site/macas.php on line 2
int(15) « usou o 10 do começo, mas reclamou
--
Fatal error: Uncaught TypeError: Unsupported operand types: string + int in /home/ana/site/macas.php:4
Stack trace:
#0 {main}
thrown in /home/ana/site/macas.php on line 4
$ echo $?
255 « o "fim" nunca apareceu
- Warning: A non-numeric value encountered
- "Foi encontrado um valor não numérico". O PHP aproveitou o
10do começo e jogou fora o resto (" maçãs"), mas avisa: provavelmente não era isso que você queria. - TypeError: Unsupported operand types: string + int
- "Erro de tipo: tipos de operandos não suportados: string mais int". Não há nenhum número em
"abc": o PHP 8 se recusa a inventar um e para o programa.
No PHP 7, "abc" + 1 dava só um aviso e o resultado 1 (o texto valia zero). O PHP 8 ficou mais rigoroso: texto sem número numa conta agora é erro. Se você encontrar tutoriais antigos dizendo que "string sem número vale 0 numa soma", eles estão falando do PHP 7.
O caso "12,90" merece atenção especial no Brasil: o PHP usa ponto como separador decimal, então a vírgula é "outra coisa" e tudo depois dela é descartado. "12,90" * 2 dá 24, com Warning. Você vai consertar isso na missão final.
Experimente: troque o texto de $quantidade e veja em qual grupo ele cai: "3", " 3 ", "3.5", "3 unidades", "três", "".
<?php $quantidade = "3 unidades"; var_dump($quantidade * 2);
3. Converter você mesmo: o casting
Para converter de propósito, escreva o tipo desejado entre parênteses antes do valor. Isso se chama casting (algo como "moldar"):
- (int) $x
- Converte para inteiro.
- (float) $x
- Converte para float.
- (string) $x
- Converte para texto.
- (bool) $x
- Converte para booleano.
- (array) $x
- Converte para array (põe o valor dentro de um array).
O casting nunca dá Warning nem erro por texto estranho: você está dizendo "eu sei o que estou fazendo". Por isso, é bom conhecer as regras.
Para int
<?php var_dump((int) "42"); var_dump((int) "42abc"); var_dump((int) "abc"); var_dump((int) 3.99); var_dump((int) -3.99); var_dump((int) "3.99"); var_dump((int) true); var_dump((int) null); var_dump((int) ""); var_dump((int) "1e3"); var_dump((int) "0x1A"); var_dump((int) "012");
$ php para-int.php int(42) int(42) « pega o número do começo, em silêncio int(0) « sem número: 0 int(3) « corta a parte decimal (não arredonda!) int(-3) « corta em direção ao zero int(3) int(1) int(0) int(0) int(1000) « entende notação científica int(0) « NÃO entende hexadecimal em texto int(12) « nem octal: o zero à esquerda é ignorado
O mais importante: (int) corta, não arredonda. (int) 3.99 é 3. Para arredondar, use (int) round(3.99) (aula int e float).
Para float, string e bool
<?php var_dump((float) "3.14"); var_dump((float) "3,14"); var_dump((float) 5); var_dump((string) 42); var_dump((string) 3.0); var_dump((string) true); var_dump((string) false); var_dump((string) null); var_dump((bool) "0"); var_dump((bool) "abc");
$ php outros.php float(3.14) float(3) « a vírgula interrompe: só o 3 foi lido float(5) string(2) "42" string(1) "3" « 3.0 vira "3", sem o ".0" string(1) "1" « true vira "1" string(0) "" « false vira texto vazio string(0) "" « null também bool(false) « "0" é falso bool(true)
| Valor | (int) | (float) | (string) | (bool) |
|---|---|---|---|---|
"42" | 42 | 42.0 | "42" | true |
"42abc" | 42 | 42.0 | "42abc" | true |
"abc" | 0 | 0.0 | "abc" | true |
"0" | 0 | 0.0 | "0" | false |
"" | 0 | 0.0 | "" | false |
3.99 | 3 | 3.99 | "3.99" | true |
true | 1 | 1.0 | "1" | true |
false | 0 | 0.0 | "" | false |
null | 0 | 0.0 | "" | false |
Converter para int um float que não cabe num inteiro (ou o NAN) agora dá Warning, porque o resultado é lixo:
$ php grande.php « var_dump((int) 1e20); Warning: The float 1.0E+20 is not representable as an int, cast occurred in /home/ana/site/grande.php on line 2 int(7766279631452241920)
Not representable as an int = "não pode ser representado como int".
Missão: a idade veio do formulário como texto. Converta-a para inteiro antes de somar, guardando em $idade, para o var_dump do ano que vem mostrar int(30). Use (int) ou intval.
<?php $idadeDoFormulario = "29"; $idade = $idadeDoFormulario; var_dump($idade); var_dump($idade + 1);
<?php $idadeDoFormulario = "29"; $idade = (int) $idadeDoFormulario; var_dump($idade); var_dump($idade + 1);
4. As funções de conversão: intval, floatval, strval, boolval
Cada casting tem uma função equivalente. intval("42") é o mesmo que (int) "42". A vantagem das funções é poderem ser passadas para outras funções (como array_map("intval", $lista), em Funções de Array) e, no caso do intval, escolher a base do número:
<?php
var_dump(intval("42"));
var_dump(intval("12abc"));
var_dump(intval("0x1A", 16));
var_dump(intval("101", 2));
var_dump(intval("012", 0));
var_dump(floatval("1.5kg"));
var_dump(strval(10));
var_dump(boolval([]));
$ php funcoes.php int(42) int(12) int(26) « lido como hexadecimal (base 16) int(5) « lido como binário (base 2) int(10) « base 0: o PHP olha o prefixo; "012" é octal float(1.5) string(2) "10" bool(false) « array vazio é falso
- intval($x, $base)
- Converte para int. A base (2, 8, 10, 16…) só vale para textos; o padrão é 10. Com base 0, o PHP decide pelo prefixo (
0x,0,0b). - floatval($x)
- O mesmo que
(float). - strval($x)
- O mesmo que
(string). - boolval($x)
- O mesmo que
(bool).
5. settype: mudar o tipo da própria variável
O casting e as funções devolvem um valor novo; a variável original continua como estava. O settype ("definir o tipo") é diferente: ele muda a própria variável.
<?php $x = "123"; settype($x, "integer"); var_dump($x);
$ php settype.php int(123) « a variável $x agora guarda um int
Os nomes aceitos são "int" ou "integer", "float", "string", "bool" ou "boolean", "array" e "null". Ele devolve true quando consegue. É pouco usado: $x = (int) $x; faz o mesmo e é mais claro.
Qual usar?
| Situação | Use |
|---|---|
| Converter um valor (o mais comum) | (int) $x, (float) $x, (string) $x |
| Ler um número em outra base | intval($x, 16) |
| Converter todos os itens de um array | array_map("intval", $lista) |
| Validar o que veio do usuário antes de converter | is_numeric($x) ou filter_var (veja Validar Dados) |
| Mudar o tipo da própria variável | $x = (int) $x; (ou settype) |
(int) "abc" dá 0 sem reclamar. Se a cliente digitou "abc" no campo idade, converter em silêncio esconde o problema. Primeiro confira (is_numeric), depois converta.
6. declare(strict_types=1): o modo rigoroso (só apresentação)
No PHP moderno, você pode dizer o tipo que uma função espera receber (aula Tipos e Retorno). Por padrão, o PHP ainda faz conversão automática nessa entrada: se a função espera int e recebe "5", ele converte:
<?php
function dobro(int $n): int
{
return $n * 2;
}
var_dump(dobro(5));
var_dump(dobro("5"));
var_dump(dobro("cinco"));
$ php sem-strict.php
int(10)
int(10) « "5" foi convertido para 5
Fatal error: Uncaught TypeError: dobro(): Argument #1 ($n) must be of type int, string given, called in /home/ana/site/sem-strict.php on line 8 and defined in /home/ana/site/sem-strict.php:2
Stack trace:
#0 /home/ana/site/sem-strict.php(8): dobro('cinco')
#1 {main}
thrown in /home/ana/site/sem-strict.php on line 2
Com a linha declare(strict_types=1); no topo do arquivo, o PHP desliga essa conversão nas chamadas de função: o tipo tem que ser exatamente o pedido. Até "5" é recusado:
<?php
declare(strict_types=1);
function dobro(int $n): int
{
return $n * 2;
}
var_dump(dobro(5));
var_dump(dobro("5"));
$ php com-strict.php
int(10)
Fatal error: Uncaught TypeError: dobro(): Argument #1 ($n) must be of type int, string given, called in /home/ana/site/com-strict.php on line 9 and defined in /home/ana/site/com-strict.php:4
Stack trace:
#0 /home/ana/site/com-strict.php(9): dobro('5')
#1 {main}
thrown in /home/ana/site/com-strict.php on line 4
- declare(…)
- "Declarar": dá uma instrução ao PHP sobre como ler este arquivo.
- strict_types=1
- "Tipos estritos: ligado". Vale só para o arquivo onde está escrito.
- must be of type int, string given
- "Deve ser do tipo int; foi dada uma string".
Três coisas para saber agora:
- Ele precisa ser a primeira instrução do arquivo, logo depois do
<?php. Senão:Fatal error: strict_types declaration must be the very first statement in the script. - Ele vale para chamadas de função (as suas e as do PHP:
strlen(123)vira TypeError). Não muda os operadores:"10" + 5continua dando15. - Muitos projetos modernos e frameworks colocam essa linha em todos os arquivos. Ela pega erros cedo, em vez de deixar o PHP "adivinhar". Você vai usá-la a partir de Tipos e Retorno.
Quando dá errado
Warning: A non-numeric value encountered
O que significa: numa conta, uma string começava com número mas tinha mais coisa depois ("10 maçãs", "12,90", "5 kg"). O PHP usou só o número do começo.
Como consertar: limpe o texto antes. Para vírgula decimal: (float) str_replace(",", ".", $preco). Para unidades, separe o número do texto.
Fatal error: Uncaught TypeError: Unsupported operand types: string + int
O que significa: numa conta, uma string sem nenhum número no começo ("abc", "", "R$ 10").
Como consertar: confira o valor com var_dump. Valide com is_numeric antes de calcular. Repare que "R$ 10" não começa com número: tire o R$ antes.
TypeError: ...(): Argument #1 (...) must be of type int, string given
O que significa: uma função que exige int recebeu uma string que não dá para converter, ou o arquivo tem strict_types=1 e a string não é aceita de jeito nenhum.
Como consertar: converta antes de chamar: dobro((int) $x) (depois de validar).
Fatal error: strict_types declaration must be the very first statement in the script
$ cat fora-do-lugar.php
<?php
echo "oi\n";
declare(strict_types=1);
$ php fora-do-lugar.php
Fatal error: strict_types declaration must be the very first statement in the script in /home/ana/site/fora-do-lugar.php on line 3
Stack trace:
#0 {main}
Como consertar: mova o declare para logo depois do <?php.
O que significa: (int) cortou a parte decimal (3.99 → 3), parou na vírgula ("3,5" → 3) ou o texto não tinha número ("abc" → 0).
Como consertar: arredonde com round, troque a vírgula por ponto e valide antes.
Referência rápida
| Escrita | Faz | Exemplo → resultado |
|---|---|---|
(int) $x, intval($x) | Para inteiro (corta decimais) | (int) "3.99" → 3 |
intval($x, $base) | Para inteiro, lendo na base dada | intval("ff", 16) → 255 |
(float) $x, floatval($x) | Para float | (float) "1.5kg" → 1.5 |
(string) $x, strval($x) | Para texto | (string) false → "" |
(bool) $x, boolval($x) | Para booleano | (bool) "0" → false |
(array) $x | Para array | (array) "Ana" → ["Ana"] |
settype($x, "int") | Muda o tipo da própria variável | |
declare(strict_types=1); | Desliga a conversão automática nas chamadas de função do arquivo |
Exercícios
1. Para inteiro
Complete para converter $texto em inteiro com casting:
2. Ponto ou mais?
Qual operador faz "10" ? 5 dar "105"?
3. Quanto vale (int) 7.9?
4. O que acontece com "abc" + 1 no PHP 8?
5. Com declare(strict_types=1); no topo, o que dá "10" + 5?
Missão final: o preço com vírgula
Missão: o preço veio do formulário escrito do jeito brasileiro, "12,90", e a conta dá Total: 24 com um Warning. Antes de multiplicar, troque a vírgula por ponto com str_replace(",", ".", $preco) e converta o resultado para float com (float). A saída deve ser Total: 25.8, sem avisos.
<?php $preco = "12,90"; $total = $preco * 2; echo "Total: $total\n";
<?php
$preco = "12,90";
$preco = (float) str_replace(",", ".", $preco);
$total = $preco * 2;
echo "Total: $total\n";
Resumo
- O PHP converte sozinho conforme o operador:
+quer número,.quer texto,ifquer booleano. - Texto numérico (
"10") vira número em silêncio; texto que começa com número ("10 maçãs") dá Warning; texto sem número ("abc") dáTypeErrorno PHP 8. - Para converter de propósito:
(int),(float),(string),(bool), ouintval,floatval,strval,boolval.(int)corta, não arredonda. settypemuda a própria variável. Converter não é validar: confira antes.declare(strict_types=1);, na primeira linha, desliga a conversão automática nas chamadas de função do arquivo.