Visibilidade
Esta aula aborda os modificadores de visibilidade em PHP (public, private e protected), o conceito de encapsulamento e a implementação de getters e setters. São apresentados exemplos práticos e boas práticas para garantir código seguro e de fácil manutenção.
Nesta aula, vamos explorar os modificadores de visibilidade em PHP: public, private e protected. Esses modificadores controlam o acesso a propriedades e métodos de classes, sendo fundamentais para o encapsulamento e a segurança do código. Entender como usá-los corretamente é essencial para escrever código orientado a objetos robusto e de fácil manutenção.
public, private, protected
Em PHP, os modificadores de visibilidade determinam de onde uma propriedade ou método pode ser acessado. O modificador public permite acesso de qualquer lugar, tanto dentro quanto fora da classe. O private restringe o acesso apenas à própria classe que o define. Já o protected permite acesso à própria classe e às suas subclasses (herança).
Vamos ver um exemplo prático:
class MinhaClasse {
public $publico = "Acessível de qualquer lugar";
private $privado = "Acessível apenas dentro da classe";
protected $protegido = "Acessível na classe e subclasses";
public function mostrarPrivado() {
return $this->privado; // Permitido
}
}
$obj = new MinhaClasse();
echo $obj->publico; // Funciona
echo $obj->mostrarPrivado(); // Funciona (método público)
// echo $obj->privado; // Erro: não pode acessar propriedade privada
// echo $obj->protegido; // Erro: não pode acessar propriedade protegida
O modificador protected é útil quando queremos que subclasses possam acessar determinados membros, mas não o código externo. Já o private é o mais restritivo, garantindo que apenas a própria classe manipule seus dados internos.
Encapsulamento
Encapsulamento é um dos pilares da programação orientada a objetos. Ele consiste em esconder os detalhes internos de uma classe e expor apenas uma interface controlada. Isso é alcançado usando modificadores de visibilidade, principalmente private e protected, combinados com métodos públicos que acessam ou modificam os dados de forma segura.
O encapsulamento traz benefícios como:
- Proteção dos dados contra acesso indevido ou inconsistente.
- Facilidade de manutenção: alterações internas não afetam o código externo.
- Maior modularidade e reuso.
Exemplo de encapsulamento com validação:
class ContaBancaria {
private $saldo;
public function __construct($saldoInicial = 0) {
$this->saldo = max(0, $saldoInicial); // Garante saldo não negativo
}
public function depositar($valor) {
if ($valor > 0) {
$this->saldo += $valor;
return true;
}
return false;
}
public function getSaldo() {
return $this->saldo;
}
}
$conta = new ContaBancaria(100);
$conta->depositar(50);
echo $conta->getSaldo(); // 150
Note que o saldo nunca pode ser acessado diretamente, apenas através de métodos que garantem regras de negócio.
Getters e setters
Getters e setters são métodos públicos que permitem acessar e modificar propriedades privadas ou protegidas. Eles são a forma mais comum de implementar encapsulamento. Um getter retorna o valor da propriedade; um setter define um novo valor, podendo incluir validações.
Exemplo de getters e setters:
class Pessoa {
private $nome;
private $idade;
// Getter para nome
public function getNome() {
return $this->nome;
}
// Setter para nome
public function setNome($nome) {
$this->nome = trim($nome);
}
// Getter para idade
public function getIdade() {
return $this->idade;
}
// Setter para idade com validação
public function setIdade($idade) {
if ($idade >= 0 && $idade <= 150) {
$this->idade = $idade;
} else {
throw new InvalidArgumentException("Idade inválida");
}
}
}
$pessoa = new Pessoa();
$pessoa->setNome("João");
$pessoa->setIdade(25);
echo $pessoa->getNome() . " tem " . $pessoa->getIdade() . " anos.";
No PHP moderno, é comum usar type hints e declarações de tipos nos getters e setters para maior segurança.
Boas práticas
Ao trabalhar com visibilidade e encapsulamento, algumas boas práticas incluem:
- Prefira propriedades privadas por padrão: só torne algo público se houver uma necessidade clara.
- Use getters e setters consistentes: mesmo que inicialmente não haja validação, eles permitem adicionar lógica futuramente sem quebrar o código.
- Evite setters para propriedades que não devem ser alteradas: nesse caso, forneça apenas getters e defina o valor no construtor.
- Não exponha referências a objetos mutáveis: se uma propriedade é um array ou objeto, retorne uma cópia ou uma versão imutável.
- Documente a visibilidade: use comentários ou anotações para explicar o propósito de cada membro.
Exemplo de boa prática com imutabilidade:
class Configuracao {
private array $dados;
public function __construct(array $dados) {
$this->dados = $dados;
}
public function get(string $chave, $default = null) {
return $this->dados[$chave] ?? $default;
}
// Não fornece setter para manter imutável
}
$config = new Configuracao(['db_host' => 'localhost']);
echo $config->get('db_host');
Seguir essas práticas ajuda a criar código mais seguro, de fácil manutenção e com menos bugs.
Referências
- PHP: Visibilidade - Manual
- PHP: Propriedades - Manual
- PHP: Classes e Objetos - Básico
- PHP: Construtores e Destrutores
- PHP: Declarações de Tipo
Exercícios
-
Crie uma classe
Carrocom propriedades privadasmarca,modeloeano. Implemente getters e setters para todas elas, validando que o ano seja maior que 1886.✓ Resposta:class Carro { private $marca; private $modelo; private $ano; public function getMarca() { return $this->marca; } public function setMarca($marca) { $this->marca = $marca; } public function getModelo() { return $this->modelo; } public function setModelo($modelo) { $this->modelo = $modelo; } public function getAno() { return $this->ano; } public function setAno($ano) { if ($ano > 1886) { $this->ano = $ano; } else { throw new InvalidArgumentException("Ano deve ser maior que 1886"); } } } -
Explique a diferença entre
privateeprotectede dê um exemplo onde o uso deprotectedé mais adequado.✓ Resposta:privaterestringe o acesso apenas à classe que define o membro, enquantoprotectedpermite acesso também às subclasses. Um exemplo ondeprotectedé mais adequado: uma classe baseAnimalcom um métodoemitirSomque é sobrescrito pelas subclasses. O método pode serprotectedpara que as subclasses o acessem, mas não o código externo. -
Implemente uma classe
Contadorcom uma propriedade privada$valorinicializada em 0. Crie métodos públicosincrementar()egetValor(). O métodoincrementardeve aumentar o valor em 1 e retornar o novo valor.✓ Resposta:class Contador { private $valor = 0; public function incrementar() { $this->valor++; return $this->valor; } public function getValor() { return $this->valor; } } -
Crie uma classe
Produtocom propriedades privadasnome,precoequantidade. Implemente um método públicocalcularTotal()que retorna o preço vezes a quantidade. Use encapsulamento adequado.✓ Resposta:class Produto { private $nome; private $preco; private $quantidade; public function __construct($nome, $preco, $quantidade) { $this->nome = $nome; $this->preco = $preco; $this->quantidade = $quantidade; } public function getNome() { return $this->nome; } public function getPreco() { return $this->preco; } public function getQuantidade() { return $this->quantidade; } public function calcularTotal() { return $this->preco * $this->quantidade; } } -
Escreva um código que demonstre a tentativa de acesso a uma propriedade
privatefora da classe e o erro gerado. Em seguida, mostre como acessá-la corretamente através de um método público.✓ Resposta:class Exemplo { private $segredo = "valor secreto"; public function getSegredo() { return $this->segredo; } } $obj = new Exemplo(); // echo $obj->segredo; // Gera erro: Cannot access private property // Forma correta: echo $obj->getSegredo(); // Exibe "valor secreto"