Visibilidade Assimétrica de Propriedades no PHP 8.4

Como o PHP 8.4 permite declarar visibilidades diferentes para leitura e escrita de uma propriedade com private(set) e protected(set), eliminando getters que só existiam para expor leitura pública.

Antes do PHP 8.4, uma propriedade só tinha uma visibilidade só: se ela era public, qualquer código de fora podia ler e escrever nela; para impedir a escrita externa, a única saída era torná-la private e criar um getter público. A visibilidade assimétrica resolve isso permitindo declarar visibilidades diferentes para leitura e escrita na mesma propriedade, usando a sintaxe private(set) ou protected(set) junto da visibilidade de leitura.

Como funciona

A visibilidade de escrita vem entre a visibilidade de leitura e o tipo, sempre seguida de (set). A regra é simples: a visibilidade de escrita precisa ser igual ou mais restrita que a de leitura, e a propriedade precisa ter um tipo declarado:

class Produto
{
    public function __construct(
        public private(set) string $nome,
        public private(set) float $preco,
    ) {}
}

$produto = new Produto('Teclado Mecânico', 350.0);
echo $produto->nome; // Teclado Mecânico — leitura funciona de fora

$produto->nome = 'Outro nome'; // Error: Cannot modify private(set) property

Qualquer código pode ler $produto->nome, mas só a própria classe Produto pode atribuir um novo valor a ela — sem precisar escrever um getter só para expor a leitura.

Forma curta: omitindo o "public"

Como o caso mais comum é "leitura pública, escrita privada", o PHP permite omitir o public e escrever só private(set), que já implica leitura pública:

class Pedido
{
    private(set) string $status = 'pendente';

    public function confirmar(): void
    {
        $this->status = 'confirmado';
    }
}

$pedido = new Pedido();
echo $pedido->status; // pendente
$pedido->confirmar();
echo $pedido->status; // confirmado

$pedido->status = 'cancelado'; // Error: Cannot modify private(set) property

protected(set) para hierarquias

Quando subclasses também precisam poder escrever na propriedade, mas o mundo externo continua só podendo ler, o certo é protected(set):

class Conta
{
    public protected(set) float $saldo = 0.0;

    public function depositar(float $valor): void
    {
        $this->saldo += $valor;
    }
}

class ContaPremium extends Conta
{
    public function aplicarBonus(float $valor): void
    {
        $this->saldo += $valor * 1.1; // subclasse pode escrever
    }
}

$conta = new ContaPremium();
$conta->depositar(100.0);
echo $conta->saldo; // 100 — leitura pública funciona normalmente

Combinando com readonly

Visibilidade assimétrica e readonly resolvem problemas diferentes: readonly trava a propriedade depois da primeira atribuição (mesmo dentro da própria classe); private(set) permite reatribuições internas ilimitadas, só bloqueando escrita externa. Combinar os dois cobre o caso de um objeto que muda de estado internamente, mas nunca aceita reatribuição direta de fora nem depois de inicializado uma vez fora do construtor:

class Contador
{
    public private(set) int $valor = 0;

    public function incrementar(): void
    {
        $this->valor++; // permitido: escrita interna, sem readonly
    }
}

Quando usar

Cuidados

A visibilidade assimétrica exige tipo declarado na propriedade — não funciona em propriedades sem tipo. Ela também não pode ser aplicada a propriedades static. Interfaces podem declarar visibilidade de leitura em uma propriedade abstrata, mas isso não é o mesmo que promessa de imutabilidade: sem readonly, o valor ainda pode mudar internamente a qualquer momento — a garantia é só sobre quem pode escrever, não sobre quantas vezes o valor pode mudar.

Compatibilidade

Visibilidade assimétrica foi introduzida no PHP 8.4 (lançado em novembro de 2024) e exige essa versão ou superior; não há como fazer polyfill dessa sintaxe em versões anteriores.

documentação oficial

Conclusão

Visibilidade assimétrica fecha uma lacuna que existia há anos no sistema de tipos do PHP: até então, expor leitura pública sem abrir mão do controle sobre a escrita exigia getters inteiros só para isso. Combinada com property hooks e constructor promotion, ela deixa classes de dados mais enxutas e comunica o contrato de mutabilidade direto na assinatura da propriedade.

Tecnologia:
php

Deixe seu Comentário!

Dúvida, sugestão ou só um "valeu!" — tudo é bem-vindo por aqui.

Comentário
Nome
Email
lock Seu e-mail não será publicado.