Herança
Esta aula aborda o conceito de herança em PHP, explicando como criar hierarquias de classes usando a palavra-chave 'extends', acessar métodos e propriedades da classe pai com 'parent', sobrescrever métodos e decidir quando usar herança de forma apropriada.
Herança é um dos pilares da programação orientada a objetos (POO) que permite que uma classe (chamada classe filha ou subclasse) herde atributos e métodos de outra classe (classe pai ou superclasse). Em PHP, a herança é implementada com a palavra-chave extends. Isso promove reutilização de código, organização e facilita a manutenção.
Nesta aula, exploraremos como usar extends para criar subclasses, como invocar métodos da classe pai com parent, como sobrescrever comportamentos e, principalmente, quando faz sentido aplicar herança em seus projetos.
extends
A palavra-chave extends é usada na declaração de uma classe para indicar que ela herda de outra classe. A classe filha ganha acesso a todos os métodos e propriedades públicas e protegidas da classe pai (a menos que sejam redeclarados).
Exemplo básico:
<?php
class Animal {
public $nome;
public function __construct($nome) {
$this->nome = $nome;
}
public function fazerSom() {
return "Som genérico";
}
}
class Cachorro extends Animal {
public function fazerSom() {
return "Au au";
}
}
$dog = new Cachorro("Rex");
echo $dog->nome; // Rex
echo $dog->fazerSom(); // Au au
?>No exemplo, Cachorro herda a propriedade $nome e o construtor de Animal. A herança permite que não precisemos redefinir o construtor em Cachorro (a menos que queiramos modificar).
parent
A palavra-chave parent é usada dentro de uma classe filha para referenciar a classe pai. É especialmente útil quando queremos chamar um método da classe pai que foi sobrescrito, ou acessar o construtor original.
Exemplo:
<?php
class Animal {
protected $tipo;
public function __construct($tipo) {
$this->tipo = $tipo;
}
public function getInfo() {
return "Tipo: " . $this->tipo;
}
}
class Gato extends Animal {
private $nome;
public function __construct($nome, $tipo) {
parent::__construct($tipo); // chama o construtor da classe pai
$this->nome = $nome;
}
public function getInfo() {
return parent::getInfo() . " - Nome: " . $this->nome;
}
}
$gato = new Gato("Mimi", "Felino");
echo $gato->getInfo(); // Tipo: Felino - Nome: Mimi
?>Usar parent:: garante que a lógica da classe pai não seja perdida, permitindo estendê-la.
Sobrescrita
Sobrescrita (override) ocorre quando uma classe filha redefine um método ou propriedade herdada da classe pai. Em PHP, para que um método possa ser sobrescrito, ele deve ser declarado como public ou protected na classe pai. Métodos final não podem ser sobrescritos.
Exemplo:
<?php
class Veiculo {
public function mover() {
return "Veículo se movendo";
}
}
class Carro extends Veiculo {
public function mover() {
return "Carro acelerando";
}
}
$carro = new Carro();
echo $carro->mover(); // Carro acelerando
?>Note que a assinatura do método deve ser compatível (mesmo nome e, a partir do PHP 8, os tipos de parâmetros e retorno devem ser covariantes/contravariantes).
Quando usar herança
A herança deve ser usada quando existe uma relação "é um" clara entre a classe filha e a classe pai. Por exemplo, um Cachorro é um Animal. Evite usar herança apenas para reutilizar código, pois isso pode levar a hierarquias frágeis. Prefira composição quando a relação for "tem um" (ex.: um Carro tem um Motor).
Boas práticas:
- Mantenha a hierarquia rasa (poucos níveis).
- Use classes abstratas para forçar implementação de métodos.
- Evite sobrescrita excessiva; se precisar modificar muito comportamento, talvez a herança não seja adequada.
- Documente a intenção da herança.
Quando a herança é mal aplicada, o código se torna acoplado e difícil de modificar. Avalie sempre se a composição não seria mais flexível.
Referências
- PHP Manual: Herança
- PHP Manual: parent
- PHP Manual: Sobrescrita
- PHP Manual: Classes abstratas
- PHP Manual: final
Exercícios
Crie uma classe
Funcionariocom propriedadesnomeesalario, e um métodocalcularBonus()que retorna 10% do salário. Depois crie uma classeGerenteque herda deFuncionarioe sobrescrevecalcularBonus()para retornar 20% do salário. Instancie um gerente e exiba o bônus.✓ Resposta:<?php class Funcionario { public $nome; public $salario; public function __construct($nome, $salario) { $this->nome = $nome; $this->salario = $salario; } public function calcularBonus() { return $this->salario * 0.10; } } class Gerente extends Funcionario { public function calcularBonus() { return $this->salario * 0.20; } } $gerente = new Gerente("Ana", 5000); echo "Bônus do gerente: R$ " . $gerente->calcularBonus(); ?>Usando a classe
Funcionariodo exercício anterior, crie uma classeDesenvolvedorque herda deFuncionarioe não sobrescreve o métodocalcularBonus(). Instancie um desenvolvedor e chame o método. Explique o resultado.✓ Resposta:<?php class Desenvolvedor extends Funcionario { // herda tudo de Funcionario } $dev = new Desenvolvedor("Carlos", 4000); echo "Bônus do dev: R$ " . $dev->calcularBonus(); // 10% = 400 ?>O método
calcularBonus()não foi sobrescrito, então o comportamento da classe pai é usado, retornando 10% do salário.Crie uma classe
ContaBancariacom propriedadesaldo(protegida) e métodosdepositar($valor)esacar($valor). Crie uma classeContaPoupancaque herda deContaBancariae sobrescrevesacar($valor)para cobrar uma taxa de 2% sobre o valor sacado. Useparent::para reutilizar a lógica de saque.✓ Resposta:<?php class ContaBancaria { protected $saldo = 0; public function depositar($valor) { $this->saldo += $valor; } public function sacar($valor) { if ($valor <= $this->saldo) { $this->saldo -= $valor; return true; } return false; } public function getSaldo() { return $this->saldo; } } class ContaPoupanca extends ContaBancaria { public function sacar($valor) { $taxa = $valor * 0.02; $total = $valor + $taxa; return parent::sacar($total); } } $cp = new ContaPoupanca(); $cp->depositar(1000); $cp->sacar(100); echo "Saldo após saque: " . $cp->getSaldo(); // 1000 - (100 + 2) = 898 ?>Explique por que o seguinte código gera erro e corrija-o:
class A { private function metodo() {} } class B extends A { public function metodo() {} }✓ Resposta:O erro ocorre porque métodos privados não são herdados. A classe filha não pode sobrescrever um método privado; ela está definindo um método novo com o mesmo nome, mas a visibilidade não pode ser aumentada (de private para public) em uma sobrescrita. Para corrigir, torne o método
protectedoupublicna classe pai, ou remova a sobrescrita.Implemente uma classe
Formaabstrata com um método abstratocalcularArea(). Crie classesQuadradoeCirculoque herdam deFormae implementam o método. Useparentse necessário (não é obrigatório).✓ Resposta:<?php abstract class Forma { abstract public function calcularArea(); } class Quadrado extends Forma { private $lado; public function __construct($lado) { $this->lado = $lado; } public function calcularArea() { return $this->lado * $this->lado; } } class Circulo extends Forma { private $raio; public function __construct($raio) { $this->raio = $raio; } public function calcularArea() { return pi() * $this->raio * $this->raio; } } $quadrado = new Quadrado(5); echo "Área do quadrado: " . $quadrado->calcularArea(); $circulo = new Circulo(3); echo "Área do círculo: " . $circulo->calcularArea(); ?>