Modificadores de acesso: public, protected, private
1. Introdução aos modificadores de acesso em PHP
Os modificadores de acesso são um dos pilares da programação orientada a objetos em PHP. Eles controlam a visibilidade e o acesso a propriedades e métodos de uma classe, implementando o princípio de encapsulamento. O encapsulamento permite que você esconda detalhes internos de implementação e exponha apenas o que é necessário para o uso externo da classe.
PHP oferece três níveis de modificadores de acesso:
- public: acesso irrestrito de qualquer lugar
- protected: acesso permitido apenas na própria classe e em classes filhas
- private: acesso restrito exclusivamente à própria classe
Dominar esses modificadores é essencial para criar código orientado a objetos robusto, seguro e de fácil manutenção.
2. O modificador public
O modificador public é o mais permissivo. Propriedades e métodos declarados como public podem ser acessados de qualquer lugar: dentro da classe, em classes filhas e fora da classe.
<?php
class Usuario {
public string $nome;
public string $email;
public function __construct(string $nome, string $email) {
$this->nome = $nome;
$this->email = $email;
}
public function saudacao(): string {
return "Olá, {$this->nome}!";
}
}
$usuario = new Usuario("Maria", "maria@email.com");
echo $usuario->nome; // Acesso direto à propriedade pública
echo $usuario->saudacao(); // Chamada de método público
O uso típico de public é para a interface pública da classe — métodos que outras partes do sistema precisam chamar. No entanto, expor propriedades diretamente como public pode ser arriscado, pois permite que qualquer código externo modifique o estado interno da classe sem validação. Por isso, é comum usar getters e setters públicos:
<?php
class Produto {
private float $preco;
public function getPreco(): float {
return $this->preco;
}
public function setPreco(float $preco): void {
if ($preco <= 0) {
throw new InvalidArgumentException("Preço deve ser positivo");
}
$this->preco = $preco;
}
}
3. O modificador protected
O modificador protected permite acesso apenas dentro da própria classe e de classes filhas (herança). Ele é ideal para membros que devem ser compartilhados entre uma classe pai e suas subclasses, mas não devem ser expostos ao mundo externo.
<?php
class Animal {
protected string $nome;
protected int $idade;
public function __construct(string $nome, int $idade) {
$this->nome = $nome;
$this->idade = $idade;
}
protected function emitirSom(): string {
return "Som genérico";
}
}
class Cachorro extends Animal {
public function latir(): string {
// Acesso a propriedades protected da classe pai
return "{$this->nome} diz: Au au!";
}
// Sobrescrita de método protected
protected function emitirSom(): string {
return "Latido";
}
}
$dog = new Cachorro("Rex", 3);
echo $dog->latir(); // Funciona
// echo $dog->emitirSom(); // Erro! Método protected não é acessível externamente
A diferença crucial entre protected e private aparece na herança: enquanto protected permite que classes filhas acessem membros da classe pai, private bloqueia completamente esse acesso.
4. O modificador private
O modificador private oferece o mais alto nível de encapsulamento. Membros declarados como private só podem ser acessados dentro da própria classe que os define. Nem mesmo classes filhas podem acessá-los diretamente.
<?php
class ContaBancaria {
private float $saldo;
private string $senha;
public function __construct(float $saldoInicial, string $senha) {
$this->saldo = $saldoInicial;
$this->senha = $senha;
}
public function depositar(float $valor): void {
if ($valor <= 0) {
throw new InvalidArgumentException("Valor inválido");
}
$this->saldo += $valor;
}
public function sacar(float $valor, string $senha): bool {
if (!$this->validarSenha($senha)) {
return false;
}
if ($valor > $this->saldo) {
return false;
}
$this->saldo -= $valor;
return true;
}
private function validarSenha(string $senha): bool {
return $this->senha === $senha;
}
}
class ContaPoupanca extends ContaBancaria {
public function aplicarRendimento(): void {
// ERRO! Não é possível acessar $this->saldo diretamente
// $this->saldo *= 1.01; // Isso causaria erro
}
}
O uso de private é fundamental para ocultar detalhes internos de implementação, como validações, cálculos auxiliares e dados sensíveis.
5. Comportamento em herança e sobrescrita de métodos
Cada modificador de acesso se comporta de forma diferente quando uma classe é estendida:
- public: Mantém-se público na classe filha. Pode ser sobrescrito livremente.
- protected: Permanece protegido na classe filha. Pode ser sobrescrito.
- private: Não é herdado pela classe filha. Métodos
privatenão podem ser sobrescritos.
<?php
class Pai {
public function metodoPublico(): string {
return "Pai público";
}
protected function metodoProtegido(): string {
return "Pai protegido";
}
private function metodoPrivado(): string {
return "Pai privado";
}
public function testarPrivado(): string {
return $this->metodoPrivado(); // Funciona: acesso dentro da própria classe
}
}
class Filho extends Pai {
public function metodoPublico(): string {
return "Filho público (sobrescrito)";
}
protected function metodoProtegido(): string {
return "Filho protegido (sobrescrito)";
}
// Não é possível sobrescrever metodoPrivado()
// private function metodoPrivado() - Isso criaria um novo método, não sobrescreve
public function testarAcessos(): string {
return $this->metodoPublico() . " | " .
$this->metodoProtegido() . " | " .
// $this->metodoPrivado(); // ERRO! Não acessível
"";
}
}
Uma regra importante: ao sobrescrever um método, você não pode reduzir sua visibilidade. Um método public não pode se tornar protected ou private na classe filha, e um método protected não pode se tornar private.
6. Modificadores de acesso em propriedades tipadas (PHP 7.4+)
Desde o PHP 7.4, é possível declarar tipos para propriedades, combinando com modificadores de acesso para maior segurança e clareza:
<?php
class Pessoa {
public string $nome;
protected int $idade;
private string $cpf;
private array $telefones = [];
public function __construct(string $nome, int $idade, string $cpf) {
$this->nome = $nome;
$this->idade = $idade;
$this->cpf = $cpf;
}
public function adicionarTelefone(string $telefone): void {
$this->telefones[] = $telefone;
}
}
Com o PHP 8.0, os construtores promovidos simplificam a declaração:
<?php
class Cliente {
public function __construct(
public string $nome,
protected string $email,
private string $documento
) {}
public function getDocumentoMascarado(): string {
return substr($this->documento, 0, 3) . '***';
}
}
$cliente = new Cliente("João", "joao@email.com", "12345678901");
echo $cliente->nome; // Acessível
// echo $cliente->email; // Erro! protected
// echo $cliente->documento; // Erro! private
echo $cliente->getDocumentoMascarado(); // 123***
7. Boas práticas e padrões comuns
A principal boa prática ao usar modificadores de acesso é o princípio do menor privilégio: comece sempre com o modificador mais restritivo (private) e evolua conforme necessário.
<?php
// Versão inicial: tudo private
class Pedido {
private array $itens = [];
private float $total = 0.0;
public function adicionarItem(string $produto, float $preco): void {
$this->itens[] = ['produto' => $produto, 'preco' => $preco];
$this->recalcularTotal();
}
private function recalcularTotal(): void {
$this->total = array_sum(array_column($this->itens, 'preco'));
}
}
// Se uma subclasse precisar acessar $itens, mude para protected
class PedidoInternacional extends Pedido {
protected function calcularFrete(): float {
// Agora pode acessar $this->itens se for protected
return count($this->itens) * 10.0;
}
}
Outras práticas recomendadas:
- Use public apenas para a API essencial da classe — métodos que outras classes precisam chamar
- Use protected para métodos de hook ou template method que subclasses podem personalizar
- Use private para detalhes internos — validações, cálculos auxiliares, dados sensíveis
- Sempre prefira getters/setters públicos a propriedades públicas para manter controle sobre o acesso
<?php
// Exemplo de refatoração: de público para privado com getters/setters
class Configuracao {
private array $dados = [];
public function __construct(array $dados) {
$this->dados = $dados;
}
public function get(string $chave, mixed $default = null): mixed {
return $this->dados[$chave] ?? $default;
}
public function set(string $chave, mixed $valor): void {
$this->dados[$chave] = $valor;
}
}
Dominar os modificadores de acesso é fundamental para escrever código PHP orientado a objetos que seja seguro, sustentável e que respeite os princípios de encapsulamento. Comece restringindo ao máximo e só aumente a visibilidade quando houver uma necessidade real.
Referências
- PHP: Visibilidade (Manual oficial) — Documentação oficial do PHP sobre os três modificadores de acesso, com exemplos detalhados e notas sobre comportamento em herança.
- PHP: Propriedades tipadas (PHP 7.4+) — Documentação oficial sobre a declaração de tipos em propriedades, combinada com modificadores de acesso.
- PHP: Construtores promovidos (PHP 8.0+) — Documentação oficial sobre a sintaxe de construtores promovidos e como eles integram modificadores de acesso.
- Encapsulamento em PHP: Guia completo (DevMedia) — Artigo técnico explicando encapsulamento e modificadores de acesso com exemplos práticos em PHP.
- PHP OOP: Visibility and Inheritance (PHP The Right Way) — Seção do guia "PHP The Right Way" sobre visibilidade e herança, com boas práticas recomendadas pela comunidade.
- Entendendo modificadores de acesso em PHP (Alura) — Tutorial da Alura explicando cada modificador de acesso com exemplos didáticos e dicas de boas práticas.
- PHP: Sobrescrita de métodos e visibilidade (Stack Overflow) — Discussão técnica no Stack Overflow sobre as regras de sobrescrita e restrições de visibilidade em PHP.