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.

Você vai aprender
  • Os operadores +, -, *, /, % e **.
  • A ordem das contas (multiplicação antes da soma) e o uso de parênteses.
  • Quando a divisão dá int e quando dá float; o intdiv.
  • Como o resto (%) funciona, inclusive com números negativos.
  • A diferença entre ++$a e $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

OperadorNomeExemploResultado
+Soma (adição)7 + 310
-Subtração7 - 34
*Multiplicação7 * 321
/Divisão7 / 32.3333333333333335
%Resto da divisão (módulo)7 % 31
**Potência (exponenciação)7 ** 3343
<?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:

  1. Parênteses ( ): o que está dentro vem primeiro.
  2. Potência **.
  3. Multiplicação, divisão e resto * / %, da esquerda para a direita.
  4. 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:

PerguntaContaExemplo
O número é par?$n % 2 === 010 % 2 → 0 (par); 7 % 2 → 1 (ímpar)
É múltiplo de 5?$n % 5 === 0pintar uma linha da tabela a cada 5
Quantos minutos sobram depois das horas cheias?$minutos % 60135 % 60 → 15
Qual o último algarismo?$n % 101234 % 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
EscritaNomeO que fazCom $a = 5, a expressão valeDepois, $a vale
++$apré-incrementosoma 1, depois devolve66
$a++pós-incrementodevolve, depois soma 156
--$apré-decrementosubtrai 1, depois devolve44
$a--pós-decrementodevolve, depois subtrai 154

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++).

Não misture ++ 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

A conta deu um número diferente do esperado

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

OperadorFazExemplo → resultado
$a + $bSoma7 + 3 → 10
$a - $bSubtração7 - 3 → 4
$a * $bMultiplicação7 * 3 → 21
$a / $bDivisão7 / 2 → 3.5
intdiv($a, $b)Divisão inteiraintdiv(7, 2) → 3
$a % $bResto (sinal do primeiro)-7 % 3 → -1
fmod($a, $b)Resto com decimaisfmod(7.5, 2) → 1.5
$a ** $bPotência2 ** 10 → 1024
-$aTroca 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:

echo 5 2;

2. Par ou ímpar

Complete para obter o resto de $n dividido por 2:

$resto = $n 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; intdiv dá só a parte inteira.
  • O resto tem o sinal do primeiro número; para decimais, fmod.
  • ++$a soma e devolve o novo; $a++ devolve o antigo e depois soma. Sozinhos na linha, são iguais.
  • ++ em texto não numérico dá Deprecated no PHP 8.5; use str_increment.