PHP Operadores Aritméticos
O caixa da lojinha precisa somar os produtos, dar desconto, dividir em parcelas e contar quantas vendas foram feitas no dia. Para isso, o PHP tem os operadores aritméticos: os sinais das contas. Alguns são iguais aos da escola (+ e -), outros mudam (* no lugar de ×, / no lugar de ÷), e há alguns novos: o resto (%), a potência (**) e o incremento (++). Nesta aula você aprende todos eles, a ordem em que o PHP faz as contas e algumas surpresas que pegam quem está começando.
- Os operadores
+,-,*,/,%e**. - A ordem das contas (multiplicação antes da soma) e o uso de parênteses.
- Quando a divisão dá
inte quando dáfloat; ointdiv. - Como o resto (
%) funciona, inclusive com números negativos. - A diferença entre
++$ae$a++(incremento antes e depois). - O que acontece com
$s++quando$sé um texto, e o aviso do PHP 8.5.
Os programas desta aula rodaram com o PHP 8.5 na máquina fictícia da Ana, na pasta ~/site. Os tipos de número (int e float) e as surpresas dos decimais estão em int e float.
A ideia: uma calculadora com símbolos de teclado
O teclado não tem as teclas × e ÷. Por isso, as linguagens de programação usam o asterisco (*) para multiplicar e a barra (/) para dividir, como nas planilhas. Os números ao redor de um operador se chamam operandos: em 7 + 3, o operador é + e os operandos são 7 e 3.
1. Os seis operadores
| Operador | Nome | Exemplo | Resultado |
|---|---|---|---|
+ | Soma (adição) | 7 + 3 | 10 |
- | Subtração | 7 - 3 | 4 |
* | Multiplicação | 7 * 3 | 21 |
/ | Divisão | 7 / 3 | 2.3333333333333335 |
% | Resto da divisão (módulo) | 7 % 3 | 1 |
** | Potência (exponenciação) | 7 ** 3 | 343 |
<?php var_dump(7 + 3); var_dump(7 - 3); var_dump(7 * 3); var_dump(7 / 3); var_dump(7 % 3); var_dump(7 ** 3);
$ php contas.php int(10) int(4) int(21) float(2.3333333333333335) « a divisão não exata dá float int(1) « 7 dividido por 3 dá 2 e sobra 1 int(343) « 7 × 7 × 7
Os espaços em volta do operador são opcionais (7+3 também funciona), mas deixam a conta mais legível. O resultado de uma conta pode ir direto para o echo ou para uma variável:
<?php $cadernos = 3; $precoCaderno = 12.5; $total = $cadernos * $precoCaderno; $parcela = $total / 3; echo "Total: $total\n"; echo "3 parcelas de $parcela\n";
$ php caixa.php Total: 37.5 3 parcelas de 12.5
Repare: 3 * 12.5 deu 37.5, um float. Basta um operando float para o resultado ser float (aula int e float).
2. A ordem das contas
Como na escola, o PHP não faz as contas simplesmente da esquerda para a direita. Ele segue uma ordem de prioridade, chamada precedência:
- Parênteses
( ): o que está dentro vem primeiro. - Potência
**. - Multiplicação, divisão e resto
* / %, da esquerda para a direita. - Soma e subtração
+ -, da esquerda para a direita.
<?php var_dump(2 + 3 * 4); var_dump((2 + 3) * 4); var_dump(10 - 4 - 3); var_dump(100 / 10 / 2); var_dump(2 ** 3 ** 2); var_dump(-2 ** 2); var_dump((-2) ** 2);
$ php ordem.php int(14) « 3 * 4 primeiro, depois + 2 int(20) « os parênteses mandam: 5 * 4 int(3) « (10 - 4) - 3: da esquerda para a direita int(5) « (100 / 10) / 2 int(512) « 2 ** (3 ** 2) = 2 ** 9: a potência vai da DIREITA para a esquerda int(-4) « -(2 ** 2): a potência vem antes do sinal de menos! int(4) « com parênteses, (-2) ao quadrado
As duas últimas pegam muita gente: -2 ** 2 dá -4, porque o PHP calcula 2 ** 2 primeiro e depois aplica o sinal. Na dúvida, use parênteses: eles nunca atrapalham e deixam a intenção clara. A tabela completa de prioridades, incluindo os outros operadores, está em Precedência.
Missão: a cliente levou 3 cadernos de R$ 12,50 e 2 canetas de R$ 2,00. O programa calcula o total errado, porque faltam multiplicações. Corrija a conta usando as variáveis para mostrar Total: 41.5.
<?php $cadernos = 3; $precoCaderno = 12.5; $canetas = 2; $precoCaneta = 2; $total = $cadernos + $precoCaderno + $canetas + $precoCaneta; echo "Total: $total\n";
<?php $cadernos = 3; $precoCaderno = 12.5; $canetas = 2; $precoCaneta = 2; $total = $cadernos * $precoCaderno + $canetas * $precoCaneta; echo "Total: $total\n";
3. Divisão: / e intdiv
A divisão com / devolve int só quando a conta é exata entre inteiros. Nos outros casos, devolve float:
<?php var_dump(6 / 3); var_dump(7 / 2); var_dump(intdiv(7, 2)); var_dump(intdiv(-7, 2));
$ php divisao.php int(2) « exata: int float(3.5) « não exata: float int(3) « intdiv: só a parte inteira int(-3) « corta em direção ao zero (não é -4)
Em muitas linguagens, 7 / 2 entre inteiros dá 3. No PHP, dá 3.5. Quando você quer só a parte inteira ("quantas caixas cheias?"), use intdiv. Dividir por zero com /, % ou intdiv dá DivisionByZeroError; a mensagem completa e o fdiv estão em int e float.
4. O resto: %
O operador % (chamado módulo) devolve o que sobra de uma divisão inteira. Pense em 7 balas para 3 crianças: cada uma ganha 2, e sobra 1. 7 % 3 é 1.
Parece pouco útil, mas aparece o tempo todo:
| Pergunta | Conta | Exemplo |
|---|---|---|
| O número é par? | $n % 2 === 0 | 10 % 2 → 0 (par); 7 % 2 → 1 (ímpar) |
| É múltiplo de 5? | $n % 5 === 0 | pintar uma linha da tabela a cada 5 |
| Quantos minutos sobram depois das horas cheias? | $minutos % 60 | 135 % 60 → 15 |
| Qual o último algarismo? | $n % 10 | 1234 % 10 → 4 |
Resto com números negativos
No PHP, o resto tem o sinal do primeiro número (o dividendo):
<?php var_dump(-7 % 3); var_dump(7 % -3); var_dump(-7 % -3);
$ php negativos.php int(-1) « primeiro número negativo: resto negativo int(1) « primeiro número positivo: resto positivo int(-1)
Isso importa no teste de "é ímpar?": -7 % 2 dá -1, não 1. Por isso, teste ímpar com $n % 2 !== 0 em vez de $n % 2 === 1.
Resto com decimais: use fmod
O % trabalha só com inteiros. Se receber um float, ele corta a parte decimal antes, e o PHP 8.5 avisa que perdeu informação:
$ php resto-float.php « var_dump(7.5 % 2); Deprecated: Implicit conversion from float 7.5 to int loses precision in /home/ana/site/resto-float.php on line 2 int(1)
Implicit conversion from float 7.5 to int loses precision = "conversão implícita de float 7.5 para int perde precisão". Para o resto com decimais, use fmod(7.5, 2), que dá float(1.5).
5. Potência: **
$a ** $b é "$a elevado a $b": 2 ** 10 é 2 multiplicado por ele mesmo 10 vezes, 1024. O expoente pode ser negativo ou decimal: 2 ** -1 dá 0.5 e 9 ** 0.5 (raiz quadrada) dá 3.0. Existe também a função pow(2, 10), que faz o mesmo, e sqrt(16) para a raiz quadrada.
6. Os sinais - e + sozinhos
Na frente de um único valor, - troca o sinal (-$x) e + não muda nada, mas converte para número: +"5" dá int(5). São os operadores unários (de um operando só).
7. Incremento e decremento: ++ e --
Somar 1 a uma variável é tão comum (contar visitas, itens, voltas de um laço) que existe um atalho: $a++ faz o mesmo que $a = $a + 1. E $a-- subtrai 1. Mas há um detalhe: o ++ pode vir antes ou depois da variável, e isso muda o valor que a expressão devolve:
<?php $a = 5; echo $a++, "\n"; echo $a, "\n"; $b = 5; echo ++$b, "\n"; echo $b, "\n";
$ php incremento.php 5 « $a++: mostrou o valor ANTIGO (5) e depois somou 6 « agora $a vale 6 6 « ++$b: somou PRIMEIRO e mostrou o novo (6) 6
| Escrita | Nome | O que faz | Com $a = 5, a expressão vale | Depois, $a vale |
|---|---|---|---|---|
++$a | pré-incremento | soma 1, depois devolve | 6 | 6 |
$a++ | pós-incremento | devolve, depois soma 1 | 5 | 6 |
--$a | pré-decremento | subtrai 1, depois devolve | 4 | 4 |
$a-- | pós-decremento | devolve, depois subtrai 1 | 5 | 4 |
Pense numa catraca de ônibus com contador: $a++ é "anote o número que está no visor e depois gire a catraca"; ++$a é "gire a catraca e anote o número novo".
Quando o ++ está sozinho na linha ($visitas++;), não há diferença: ninguém usa o valor devolvido. A diferença só aparece quando a expressão é usada (num echo, numa conta, numa atribuição). O lugar mais comum do ++ é o laço for (aula for): for ($i = 1; $i <= 10; $i++).
++ com outras contas na mesma linha
Uma linha como $j = $i++ + ++$i; funciona (com $i = 1, dá $j = 4 e $i = 3), mas ninguém consegue ler isso sem parar para pensar. Incremente numa linha, calcule na outra.
++ em null, bool e float
Com um float, o ++ soma 1 normalmente (1.5 vira 2.5). Com null, o ++ dá 1. Já nos outros casos, o PHP 8.5 avisa que nada aconteceu:
<?php $n = null; $n--; var_dump($n); $t = true; $t++; var_dump($t);
$ php estranhos.php Warning: Decrement on type null has no effect, this will change in the next major version of PHP in /home/ana/site/estranhos.php on line 3 NULL Warning: Increment on type bool has no effect, this will change in the next major version of PHP in /home/ana/site/estranhos.php on line 6 bool(true)
Decrement on type null has no effect = "decremento em null não tem efeito"; this will change in the next major version = "isto vai mudar na próxima versão principal". Use ++ e -- só com números.
8. ++ em texto: o "contador de letras"
O PHP tem uma herança curiosa da linguagem Perl: ++ numa string de letras e números "avança" o texto como um hodômetro de carro. "a" vira "b", "z" vira "aa", "A9" vira "B0". Mas, no PHP 8.5, isso dá aviso:
<?php $s = "a"; $s++; var_dump($s); $s = "z"; $s++; var_dump($s); $s = "A9"; $s++; var_dump($s); $s = "5"; $s++; var_dump($s);
$ php letras.php Deprecated: Increment on non-numeric string is deprecated, use str_increment() instead in /home/ana/site/letras.php on line 3 string(1) "b" Deprecated: Increment on non-numeric string is deprecated, use str_increment() instead in /home/ana/site/letras.php on line 6 string(2) "aa" « como o hodômetro: z volta para a e "vai um" Deprecated: Increment on non-numeric string is deprecated, use str_increment() instead in /home/ana/site/letras.php on line 9 string(2) "B0" int(6) « "5" é numérico: virou o número 6, sem aviso
Increment on non-numeric string is deprecated, use str_increment() instead = "incremento em string não numérica está obsoleto; use str_increment() no lugar". O comportamento ainda funciona, mas vai deixar de existir. Para "avançar" um texto de propósito, use as funções criadas para isso PHP 8.3+:
<?php
var_dump(str_increment("a"));
var_dump(str_increment("Az"));
var_dump(str_decrement("b"));
$ php str-increment.php string(1) "b" string(2) "Ba" string(1) "a"
E o -- em texto? Ele nunca funcionou para letras: "b"-- continua "b", e o PHP 8.5 avisa Deprecated: Decrement on non-numeric string has no effect and is deprecated. Use str_decrement.
Quando dá errado
O que significa: quase sempre é a ordem das contas: $a + $b / 2 divide só o $b; -2 ** 2 dá -4.
Como consertar: coloque parênteses no que deve ser feito primeiro: ($a + $b) / 2.
Fatal error: Uncaught TypeError: Unsupported operand types: array + int
$ php array-soma.php « var_dump([] + 1);
Fatal error: Uncaught TypeError: Unsupported operand types: array + int in /home/ana/site/array-soma.php:2
Stack trace:
#0 {main}
thrown in /home/ana/site/array-soma.php on line 2
O que significa: um dos operandos não é número (aqui, um array; com "abc" é string + int).
Como consertar: mostre os operandos com var_dump. Para somar os itens de um array, use array_sum (aula Funções de Array). Textos com números: veja Conversão de Tipos.
Deprecated: Increment on non-numeric string is deprecated
O que significa: você usou ++ numa variável que tem texto. Às vezes é de propósito (avançar letras); às vezes é um número que chegou como texto com algo a mais, como "5 itens".
Como consertar: para letras, str_increment($s); para números, converta antes: $n = (int) $n; $n++;.
Deprecated: Implicit conversion from float ... to int loses precision
O que significa: o % (ou outro lugar que exige inteiro) recebeu um número com casas decimais.
Como consertar: para resto com decimais, fmod; para inteiros, arredonde antes com round.
Referência rápida
| Operador | Faz | Exemplo → resultado |
|---|---|---|
$a + $b | Soma | 7 + 3 → 10 |
$a - $b | Subtração | 7 - 3 → 4 |
$a * $b | Multiplicação | 7 * 3 → 21 |
$a / $b | Divisão | 7 / 2 → 3.5 |
intdiv($a, $b) | Divisão inteira | intdiv(7, 2) → 3 |
$a % $b | Resto (sinal do primeiro) | -7 % 3 → -1 |
fmod($a, $b) | Resto com decimais | fmod(7.5, 2) → 1.5 |
$a ** $b | Potência | 2 ** 10 → 1024 |
-$a | Troca o sinal | -(-5) → 5 |
++$a / $a++ | Soma 1 (devolve o novo / o antigo) | |
--$a / $a-- | Subtrai 1 (devolve o novo / o antigo) | |
str_increment($s) | Avança um texto 8.3+ | "Az" → "Ba" |
Exercícios
1. Elevar ao quadrado
Complete para calcular 5 ao quadrado:
2. Par ou ímpar
Complete para obter o resto de $n dividido por 2:
3. Quanto vale 2 + 3 * 4?
4. Com $a = 10;, o que echo $a++; mostra?
5. Quanto vale -2 ** 2 no PHP?
6. Quanto vale -10 % 3?
Missão final: minutos em horas
Missão: o curso de PHP da Ana tem 135 minutos de vídeo. Calcule as horas cheias (com intdiv) e os minutos que sobram (com %), sem escrever 2 e 15 à mão, para mostrar 135 minutos = 2h15min. Depois troque para 200 minutos e confira (deve dar 3h20min).
<?php
$minutos = 135;
$horas = 0; // calcule
$resto = 0; // calcule
echo "$minutos minutos = {$horas}h{$resto}min\n";
<?php
$minutos = 135;
$horas = intdiv($minutos, 60);
$resto = $minutos % 60;
echo "$minutos minutos = {$horas}h{$resto}min\n";
(As chaves em {$horas}h separam o nome da variável da letra h grudada nela; veja Interpolação.)
Resumo
+ - * /são as quatro operações;%é o resto;**é a potência.- Ordem: parênteses, depois
**, depois* / %, depois+ -.-2 ** 2é-4. Na dúvida, parênteses. /dá float quando a divisão não é exata;intdivdá só a parte inteira.- O resto tem o sinal do primeiro número; para decimais,
fmod. ++$asoma e devolve o novo;$a++devolve o antigo e depois soma. Sozinhos na linha, são iguais.++em texto não numérico dáDeprecatedno PHP 8.5; usestr_increment.