PHP Operadores de Atribuição

Você já usa um operador de atribuição desde a primeira aula: o =, que guarda um valor numa variável. Mas um programa vive atualizando variáveis: o total do carrinho cresce a cada produto, o estoque diminui a cada venda, a mensagem ganha mais uma linha. Para isso, o PHP tem atalhos como += ("some a isto") e .= ("acrescente este texto"). Nesta aula você aprende todos eles, o ??= para valores padrão e a ideia das referências (&).

Você vai aprender
  • Como o = funciona por dentro (e por que $a = $b = 0 funciona).
  • Os atalhos +=, -=, *=, /=, %= e **=.
  • O .=, para ir montando um texto aos pedaços.
  • O ??=, que só atribui se a variável for null ou não existir.
  • As armadilhas do =+ e do = dentro do if.
  • A ideia da atribuição por referência, $b = &$a.

Os programas desta aula rodaram com o PHP 8.5 na máquina fictícia da Ana, na pasta ~/site. Os operadores das contas (+, *, %…) estão em Operadores Aritméticos.


A ideia: abreviações

Numa mensagem de celular, muita gente escreve "vc" em vez de "você": é a mesma palavra, só mais curta. Os operadores de atribuição combinados são abreviações. Em vez de escrever $total = $total + 5; (repetindo $total), você escreve $total += 5;. O resultado é idêntico.


1. O =, de novo, com mais detalhes

Lembre da aula de Variáveis: o = se lê "recebe". O PHP calcula tudo do lado direito e guarda o resultado na variável do lado esquerdo. Por isso, o lado esquerdo precisa ser uma variável:

$ cat invertido.php
<?php
5 = $x;
$ php invertido.php

Parse error: syntax error, unexpected token "=" in /home/ana/site/invertido.php on line 2

Um detalhe que vai ser útil: a atribuição, além de guardar o valor, também devolve esse valor. É por isso que dá para escrever várias atribuições encadeadas:

<?php
var_dump($x = 7);
$a = $b = $c = 0;
var_dump($a, $b, $c);
$ php encadeada.php
int(7)                   « "$x = 7" guardou 7 em $x e devolveu 7 para o var_dump
int(0)                   « $c = 0 devolveu 0, que foi para $b, que foi para $a
int(0)
int(0)

O encadeamento vai da direita para a esquerda: $a = ($b = ($c = 0)). É prático para zerar vários contadores de uma vez.


2. Os atalhos das contas

Cada operador aritmético tem a sua versão "com igual". A regra é sempre a mesma: $x OP= valor é o mesmo que $x = $x OP valor.

AtalhoÉ o mesmo queLeia comoCom $x = 10, fica
$x += 5;$x = $x + 5;some 5 a $x15
$x -= 3;$x = $x - 3;tire 3 de $x7
$x *= 2;$x = $x * 2;multiplique $x por 220
$x /= 4;$x = $x / 4;divida $x por 42.5
$x %= 3;$x = $x % 3;fique com o resto de $x por 31
$x **= 2;$x = $x ** 2;eleve $x ao quadrado100
<?php
$total = 10;
$total += 5;  echo $total, "\n";
$total -= 3;  echo $total, "\n";
$total *= 2;  echo $total, "\n";
$total /= 4;  var_dump($total);
$total **= 2; var_dump($total);
$n = 17;
$n %= 5;
var_dump($n);
$ php atalhos.php
15                       « 10 + 5
12                       « 15 - 3
24                       « 12 * 2
int(6)                   « 24 / 4: divisão exata, continua int
int(36)                  « 6 ao quadrado
int(2)                   « resto de 17 por 5

(Duas instruções na mesma linha, como $total += 5; echo $total, "\n";, são permitidas: o ; separa uma da outra. Aqui é só para a tabela ficar compacta.)

Esses atalhos aparecem em todo lugar onde algo "acumula": o total de um carrinho ($total += $preco;), a baixa no estoque ($estoque -= $vendidos;), um desconto ($preco *= 0.9;, que tira 10%).

Missão: monte o carrinho da Ana. Comece com $total = 0, some os três produtos (12.5, 4 e 3.5) usando += e depois dê 10% de desconto com *= 0.9. A saída deve ser Total: 18.

<?php
$total = 0;
// some os produtos com +=

// dê o desconto com *=

echo "Total: $total\n";
<?php
$total = 0;
$total += 12.5;
$total += 4;
$total += 3.5;
$total *= 0.9;
echo "Total: $total\n";

3. .=: montar um texto aos pedaços

O ponto junta textos (aula Operadores de String), e o .= é o atalho de "acrescente no fim": $msg .= "!"; é o mesmo que $msg = $msg . "!";.

<?php
$msg = "Olá";
$msg .= ", Ana";
$msg .= "!";
echo $msg, "\n";
$ php mensagem.php
Olá, Ana!

É o jeito clássico de montar um e-mail, um relatório ou um pedaço de HTML linha por linha. Mais tarde, com laços (foreach), você vai usar .= para gerar uma lista inteira.

+= não junta texto

Quem vem de JavaScript costuma escrever += para acrescentar texto. Em PHP, o + é só para números:

$ cat juntar-errado.php
<?php
$nome = "Ana";
$nome += " Souza";
$ php juntar-errado.php

Fatal error: Uncaught TypeError: Unsupported operand types: string + string in /home/ana/site/juntar-errado.php:3
Stack trace:
#0 {main}
  thrown in /home/ana/site/juntar-errado.php on line 3

Para texto, é sempre .=.


4. ??=: atribuir só se estiver vazio PHP 7.4+

O ??= é o atalho de "se não tiver valor, use este". Ele só atribui quando a variável é null ou nem existe; se já houver um valor, deixa como está. É o irmão do ??, explicado em ?? e ?->.

<?php
$config = ["tema" => "escuro"];
$config["idioma"] ??= "pt-BR";
$config["tema"] ??= "claro";
print_r($config);
$nome = null;
$nome ??= "visitante";
echo $nome, "\n";
$vazio = "";
$vazio ??= "padrão";
var_dump($vazio);
$ php padrao.php
Array
(
    [tema] => escuro     « já tinha valor: ficou "escuro"
    [idioma] => pt-BR    « não existia: recebeu o padrão
)
visitante                « era null: recebeu o padrão
string(0) ""             « "" não é null: o ??= não mexeu
$x ??= valor;
É o mesmo que $x = $x ?? valor;: "$x recebe ele mesmo, ou o valor se for null".
Não dá Warning
Mesmo que $x (ou a chave do array) não exista. Por isso é tão usado para preencher configurações que faltam.
Só olha o null
"", 0 e false são valores: o ??= não os troca (veja null).

5. A armadilha do = no if

Como a atribuição devolve o valor, ela "funciona" em lugares onde você queria uma comparação. O erro mais clássico da programação é escrever um igual só dentro do if:

<?php
$x = 3;
if ($x = 5) {
    echo "x vale $x\n";
}
$ php armadilha.php
x vale 5                 « $x era 3! o "=" trocou o valor para 5, e 5 é verdadeiro

O if ($x = 5) não pergunta nada: ele guarda 5 em $x e usa o 5 como condição (5 é verdadeiro, aula Booleanos). O PHP não reclama. Para comparar, use === (três iguais): if ($x === 5). A diferença entre =, == e === está em Comparação (== e ===).


6. Atribuição por referência: & (só a ideia)

Normalmente, $b = $a; copia o valor: depois disso, mexer em uma não muda a outra. Com um & antes da variável da direita, o PHP faz outra coisa: $b = &$a; cria um segundo nome para a mesma caixa. Mexeu numa, mexeu na outra:

<?php
$x = 1;
$y = $x;
$y = 5;
echo "cópia:      x=$x y=$y\n";
$a = 1;
$b = &$a;
$b = 5;
echo "referência: a=$a b=$b\n";
$a = 9;
echo "referência: a=$a b=$b\n";
$ php referencia.php
cópia:      x=1 y=5      « $y é uma caixa separada
referência: a=5 b=5      « mudar $b mudou $a: é a mesma caixa
referência: a=9 b=9      « e vice-versa

Pense numa caixa com duas etiquetas coladas: "a" e "b". Não importa por qual etiqueta você pega a caixa, o conteúdo é o mesmo. Um unset($b) arranca só a etiqueta "b"; a caixa e o $a continuam lá.

No dia a dia, você vai encontrar o & em dois lugares: no foreach que modifica os itens de um array (foreach ($precos as &$p), aula foreach) e em funções que alteram a variável recebida (aula Parâmetros). Fora disso, prefira as cópias: referências deixam o código mais difícil de acompanhar.


Quando dá errado

O total "zerou" em vez de somar: o =+
$ cat invertido2.php
<?php
$total = 10;
$total =+ 5;
var_dump($total);
$ php invertido2.php
int(5)                   « era para ser 15!

O que significa: os sinais foram digitados na ordem errada. =+ 5 é lido como = +5: "receba mais-cinco". O PHP não reclama, porque é um código válido.

Como consertar: o sinal da conta vem antes do igual: +=, -=, *=, .=.

Warning: Undefined variable num += ou .=
$ php contador.php           « $cont += 1;  var_dump($cont);

Warning: Undefined variable $cont in /home/ana/site/contador.php on line 2
int(1)

O que significa: $cont += 1 precisa ler o valor atual de $cont, que não existe.

Como consertar: dê um valor inicial antes: $cont = 0; (para textos, $msg = "";).

Fatal error: Uncaught TypeError: Unsupported operand types: string + string

O que significa: você usou += para juntar textos.

Como consertar: use .=.

O if sempre entra (ou nunca entra)

O que significa: provavelmente há um = sozinho na condição: if ($x = 5) atribui em vez de comparar.

Como consertar: if ($x === 5).


Referência rápida

OperadorEquivale aUso típico
$x = v—guardar um valor
$x += v$x = $x + vsomar ao total
$x -= v$x = $x - vbaixar o estoque
$x *= v$x = $x * vaplicar desconto ou juros
$x /= v$x = $x / vdividir em partes
$x %= v$x = $x % v"dar a volta" num contador
$x **= v$x = $x ** vpotência
$x .= "t"$x = $x . "t"montar um texto
$x ??= v$x = $x ?? vvalor padrão 7.4+
$b = &$a—dois nomes para a mesma variável

Exercícios

1. Baixa no estoque

Complete para tirar 2 unidades do estoque:

$estoque 2;

2. Acrescentar texto

Complete para acrescentar " Souza" no fim de $nome:

$nome " Souza";

3. Depois de $x = 4; $x *= 3; $x -= 2;, quanto vale $x?

4. Com $tema = "";, o que $tema ??= "claro"; faz?

5. Com $a = 1; $b = &$a; $b = 7;, quanto vale $a?

Missão final: a lista de compras

Missão: monte o texto da lista de compras aos pedaços com .=, a partir de $lista = "Lista: ";, acrescentando "arroz", ", feijão" e ", café" (um .= para cada). A saída deve ser Lista: arroz, feijão, café.

<?php
$lista = "Lista: ";

echo $lista, "\n";
<?php
$lista = "Lista: ";
$lista .= "arroz";
$lista .= ", feijão";
$lista .= ", café";
echo $lista, "\n";

Resumo

  • = guarda o valor da direita na variável da esquerda e devolve esse valor (por isso $a = $b = 0 funciona).
  • $x OP= v é o atalho de $x = $x OP v: +=, -=, *=, /=, %=, **=.
  • .= acrescenta texto; += com texto dá TypeError.
  • ??= atribui só se a variável for null ou não existir, sem Warning.
  • Cuidado com =+ (é "recebe mais-…") e com = dentro do if (use ===).
  • $b = &$a dá um segundo nome à mesma variável; use pouco.