PHP para Iniciantes: Operadores de Incremento/Decremento

Para começar este artigo eu gostaria de citar as palavras-chaves do título para mostrar seus significados a partir de um dicionário. A ideia aqui é te ajudar, caso precise, a compreender os profundos significados das coisas na computação. Ok, não todas as coisas, mas só sobre o que vamos abordar por agora. Tudo, ou quase tudo, tem uma palavra definida que auxilia no aprendizado. Ou seja, quando te falo pra estudar uma documentação, esteja preparado para usar, também, dicionários: a famosa documentação das linguagens naturais.

Então temos a primeira palavra-chave...

Incremento

ato, processo ou efeito de incrementar(-se) [algo] em quantidade, valor etc.

desenvolvimento, crescimento, aumento.

Na matemática é o mesmo que ACRÉSCIMO.

Então o termo "incremento" pode ser interpretado como "uma operação de somar algo a alguma coisa". Incremento é uma operação de soma.

Mas o que acontece de especial nessa soma que precise de uma palavra diferente, Kiko?

O especal está no que acontece depois da soma: quem é afetado? O que é alterado? Se você incrementa uma maçã, essa maçã se transforma em uma maçã + alguma coisa. Logo, o incremento afeta diretamente o que está sendo incrementado. Daí a diferença de uma simples soma, cujo resultado pode ser usado em qualquer outro lugar.

Então qual é o resultado de um incremento, Kiko?

Isso depende. Resultado é uma palavra muito forte nesse cenário, porque o incremento por si só não foi feito para ter um retorno. Ele apenas atribui e acabou. O que você pode ter como resultado são apenas dois cenários:

  • o valor antes do incremento;
  • o valor depois do incremento.

Se você deseja recuperar o antes, então você deseja usar o pós-incremento, que é a linda arte de usar o valor anterior e depois incrementar em uma linha só. Já se você deseja recuperar o depois, então pré-incremento é o que você deseja.

E a sintaxe é bem simples! O operador de incremento, dado que refere-se a uma soma, é ++ (sim, dois símbolos de soma). Se você deseja o pós-incremento, você coloca o operador no final da variável: $a++, que pode ser lido como "primeiro me dê $a, depois faça o incremento". Já o pré-incremento, é só colocar antes da variável: ++$a, que pode ser lido como "primeiro incremente, depois me dê o valor de $a".

Tudo bem até aqui? Vamos seguir para a próxima palavra...

Decremento

diminuição gradual (em tamanho, quantidade, número ou intensidade).

(por metonímia) quantidade que se perde pelo uso ou desperdício.

Na matemática é o mesmo que DECRÉSCIMO.

Na mesma pegada que o incremento, o decremento seria o operador inverso: a subtração. E da mesmíssima forma, é uma palavra diferente pois sua operação afeta uma variável, tendo as mesmas possibilidades de captura.

O operador de decremento é -- (dois símbolos de subtração), e os esquemas de pré ou pós-decremento é o mesmo:

  • pré: --$a (primeiro subtraia, depois me dê o valor de $a);
  • pós: $a-- (primeiro me dê o valor de $a, depois subtraia).

Um pouco de matemática

Ok, agora você sabe que o incremento soma alguma coisa a uma variável e o decremento subtrai da variável, mas faz ideia de que informação é aplicada?

Por exemplo, se você tem um dado numérico, incrementá-lo é o mesmo que fazer uma soma com 1. Ou seja, ++$a ou $a++ é o mesmo que $a = $a + 1. O decremento segue o mesmo jogo: --$a ou $a-- => $a = $a - 1.

Então é sempre uma adição ou subtração numérica, Kiko?

Nem sempre. É fato que se o dado armazenado na variável for numérico, uma operação com números será o comportamento esperado. Mas e se o dado for um texto (string)?

Um pouco de gramática alfabeto

Quando você tem uma variável com um caractere armazenado, você pode brincar de "varrer o alfabeto" com o operador de incremento. Isto é, se você respeitar as limitações das tratativas.

Primeiramente, preciso alertar que isso só funciona com alfabetos da tabela plain ASCII, definida em expressão regular por [a-zA-Z]. Além disso, só funciona para incrementos. Decrementos não fazem nada.

Outro ponto importante é que não há uma transição de letras minúsculas para maiúsculas: isso sempre é preservado na casa onde está acontecendo a "soma".

Incrementar a última letra do alfabeto (z ou Z) resulta em um reset da "casa decimal somada" e um acréscimo da letra a ou A à esquerda (dependendo de estar usando maiúsculo ou minúsculo).

Esse comportamento é similar ao que acontece com as casas decimais em números, conforme expliquei na mini-aula sobre base numérica no artigo sobre tipos de dados primitivos - inteiros.

Um resuminho só pra refrescar a memória: 9 + 1 => não tem outro símbolo que represente essa soma, então adicionamos mais uma casa à esquerda => 1...9 => e depois resetamos a casa que recebeu a soma => 1..0 => 10. Com as letras seria o mesmo: z++ => a...z => aa (a ou A representam o número 0).

Dá pra dizer que o incremento com texto é uma operação matemática com uma base numérica bem grande...

Mas Kiko, e se usarmos acentuação?

Bem, não vai acontecer nada. Como falei, essas expressões só funcionam com plain ASCII, que não conta com acentuações, cedilhas, nem nada. Mas ao invés de rolar algum erro, apenas não acontece nada.

Exemplos finais

<?php

$texto = 'Bb';
var_dump(++$texto); //string(Bc)

$texto = 'Bz';
var_dump(++$texto); //string(Ca) - aumenta 1 em B, que está maiúsculo, logo permanece maiúsculo, e reseta z.

$texto = 'dZ';
var_dump($texto++); // string(dZ) - pegadinha do malandro, pós-incremento xD
var_dump($texto); // string(eA)

Onde a gente pode aplicar isso, Kiko?

Seguindo boas práticas? Lugar nenhum. Se aventurando no PHP de rua? Bem, você pode escrever transições de máquina de estado monossilábicas e fazer as transições baseado nas letras.

QUE

<?php

class StatusDePedido
{
    private const LABELS = [
        'a' => 'Pendente',
        'b' => 'Aguardando pagamento',
        'c' => 'Preparando envio',
        'd' => 'À caminho',
        'e' => 'Entregue',
    ];

    public function __construct(
        private string $value
    ) {
        if (!isset(self::LABELS[$this->value])) {
            throw new Exception("Status inválido!");
        }
    }

    public function label(): string
    {
        return self::LABELS[$this->value];
    }

    public function value(): string
    {
        return $this->value;
    }

    public function upgrade(): void
    {
        $previousValue = $this->value++;
        if (!isset(self::LABELS[$this->value])) {
            $this->value = $previousValue;
        }
    }

    public function __invoke(): string
    {
        return $this->label();
    }
}

$status = new StatusDePedido('a');
var_dump($status()); // string(Pendente)

$status->upgrade();
var_dump($status()); // string(Aguardando pagamento)

$status->upgrade();
var_dump($status()); // string(Preparando envio)

$status->upgrade();
var_dump($status()); // string(À caminho)

$status->upgrade();
var_dump($status()); // string(Entregue)

$status->upgrade();
var_dump($status()); // string(Entregue), não acontece nada porque caso o incremento gere um valor inválido, eu reseto pro valor anterior

Apesar de parecer legal fazer isso, não é. Mesmo se, de alguma forma, você conseguir deixar isso legível no código... A pessoa que faz a depuração pelo banco de dados vai ver um status b e ficar pensando "Que diabo é isso!?"

Portanto, pelo futuro seguro de desenvolvimento e manutenção dos seus projetos, evite esse tipo de abordagem. Faça transições claras e que independem de um armazenamento sequencial ([1, 2, 3, ..., n] ou [a, b, c, ... ]), pois se, em algum momento, precisar colocar um status no meio do fluxo sequencial, seu código ficará bem feio, rs.


Curtiu?! Comenta e compartilha! Esse artigo me tomou um tempo considerável, o qual aproveitei que minhas filhas dormiram cedo pra caprichar. Está cada vez mais difícil parar para escrever pois elas estão dando um certo trabalho todo dia... Mas eu dou um jeito, ok? Não se preocupa.

No próximo artigo falaremos sobre Operadores lógicos, onde vou mencionar os iradíssimos operadores bit a bit de forma mais resumida. Parando pra pensar, acho que operadores lógicos deveria ser um artigo antes do bitwise... Mas já foi! Estou seguindo a estrutura da documentação oficial do PHP, alguém imaginou que essa ordem faz mais sentido, hehe. Enfim...

Inté!