Da trilha de PHP Este conceito ainda não saiu como card do dia. ir para o card de hoje

PHP POO Intermediário

Visibilidade e readonly

Em PHP, visibilidade controla quem pode acessar propriedades e métodos de uma classe. Temos public (todos acessam), protected (a própria classe e suas subclasses) e private (somente a própria classe). Escolher a visibilidade correta é o primeiro passo para encapsular bem um objeto.

Desde o PHP 8.1, o modificador readonly permite declarar propriedades que só podem ser inicializadas uma vez, normalmente no construtor. Isso elimina setters desnecessários e torna o objeto imutável depois de criado, evitando bugs causados por alterações inesperadas de estado.

No PHP 8.2 surgiram as readonly classes: ao marcar readonly class, todas as propriedades da classe ganham automaticamente o modificador readonly. Isso é útil para classes de valor (Value Objects), como Dinheiro, CPF ou Coordenada.

A combinação de visibilidade restritiva com readonly é a base da imutabilidade em PHP: os dados são definidos uma única vez e não podem mais ser alterados, o que simplifica o raciocínio sobre o código e facilita testes.

Pontos-chave

  • public é acessível de qualquer lugar; protected só de dentro da classe e subclasses; private apenas da própria classe.
  • Propriedades readonly só podem ser atribuídas uma vez, geralmente no construtor.
  • readonly class aplica readonly a todas as propriedades da classe de uma só vez.
  • Objetos imutáveis são mais seguros, previsíveis e fáceis de testar.
  • Tentar alterar uma propriedade readonly já inicializada lança Error.
visibilidade_readonly.php
<?php

declare(strict_types=1);

// readonly class: todas as propriedades são readonly automaticamente
readonly class Conta
{
    public function __construct(
        private string $titular,
        private float $saldoInicial,
    ) {}

    // Método público expõe o titular, mas não permite alterá-lo
    public function titular(): string
    {
        return $this->titular;
    }

    // protected: só subclasses podem ver o saldo bruto
    protected function saldoBruto(): float
    {
        return $this->saldoInicial;
    }

    // Retorna uma NOVA instância em vez de mutar a atual
    public function depositar(float $valor): self
    {
        return new self($this->titular, $this->saldoInicial + $valor);
    }

    public function saldoComTaxa(float $taxa): float
    {
        return $this->saldoBruto() * (1 - $taxa);
    }
}

$conta = new Conta('Ana', 1000.0);
$novaConta = $conta->depositar(500.0);

echo $conta->titular(), PHP_EOL;
echo $conta->saldoComTaxa(0.1), PHP_EOL;
echo $novaConta->saldoComTaxa(0.1), PHP_EOL;

Exercícios

  1. 1
    Fácil

    Produto com preço readonly

    Crie uma classe Produto com as propriedades nome (pública) e preco (readonly). O construtor deve receber os dois valores. Adicione um método descricao() que retorna uma string no formato Nome: R$ preco com duas casas decimais.

    Resolver
  2. 2
    Médio

    Conta bancária imutável com readonly class

    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.

    Resolver
  3. 3
    Desafio

    Value Object CPF com validação e readonly

    Implemente um Value Object Cpf como readonly class, recebendo a string no construtor. A propriedade valor deve ser privada e acessível via método valor(): string. No construtor, valide que a string tem 11 dígitos numéricos (use preg_match('/^\d{11}$/', $cpf)); se não, lance InvalidArgumentException. Implemente também equals(Cpf $outro): bool comparando os valores. Crie um try/catch demonstrando um CPF válido e um inválido.

    Resolver

Continue estudando