Médio PHP

Conta bancária imutável com readonly class

Enunciado

Transforme a classe Conta em uma readonly class com as propriedades titular (string) e saldo (float). Adicione um método depositar(float $valor): self que retorna uma nova instância com o saldo somado, sem alterar a original. Imprima o saldo da conta original e da nova.

Requisitos

  • A classe deve ser declarada como readonly class.
  • O método depositar deve retornar uma nova instância (return new self(...)).
  • A conta original não deve ser alterada.
  • O programa deve imprimir os dois saldos com number_format.

Código inicial

<?php

declare(strict_types=1);

class Conta
{
    // TODO: tornar readonly e implementar depositar
}

$c = new Conta('Ana', 1000.0);
$c2 = $c->depositar(500.0);
echo number_format($c->saldo, 2, ',', '.'), PHP_EOL;
echo number_format($c2->saldo, 2, ',', '.'), PHP_EOL;

Saída esperada

1.000,00
1.500,00
Ver dica

Em readonly class, todas as propriedades são readonly automaticamente. Para "alterar", retorne uma nova instância.

Mostrar solução
<?php

declare(strict_types=1);

// readonly class: TODAS as propriedades são readonly
readonly class Conta
{
    public function __construct(
        public string $titular,
        public float $saldo,
    ) {}

    // Não muta: devolve uma nova Conta com o saldo atualizado
    public function depositar(float $valor): self
    {
        return new self($this->titular, $this->saldo + $valor);
    }
}

$c = new Conta('Ana', 1000.0);
$c2 = $c->depositar(500.0);

echo number_format($c->saldo, 2, ',', '.'), PHP_EOL;
echo number_format($c2->saldo, 2, ',', '.'), PHP_EOL;

Passo a passo

  1. readonly class Conta marca automaticamente titular e saldo como readonly.
  2. O construtor promovido recebe e atribui os dois valores.
  3. depositar() não altera $this->saldo; cria uma nova instância com o valor somado.
  4. Como self é uma referência à própria classe, new self(...) funciona dentro dela.
  5. No programa principal, guardamos a nova conta em $c2 e imprimimos os dois saldos formatados.

Por que funciona

A imutabilidade impede que depositar modifique o objeto original. Cada operação devolve uma nova versão, o que torna o fluxo previsível e evita efeitos colaterais em outros pontos do código que compartilhem a mesma referência.

Erros comuns

  • Escrever $this->saldo += $valor; dentro de depositar: lança Error: Cannot modify readonly property.
  • Declarar readonly class e ainda colocar readonly em cada propriedade: redundante, gera erro de sintaxe em algumas versões.
  • Esquecer return na nova instância: o método retorna null e quebra o tipo self.

Outra forma de resolver

Usar uma propriedade readonly isolada em vez da classe inteira:

class Conta {
    public function __construct(
        public readonly string $titular,
        public readonly float $saldo,
    ) {}
    // ...
}

Prefira isso quando só algumas propriedades precisam ser imutáveis.

Saída esperada

1.000,00
1.500,00