Herança e polimorfismo
A herança é o cerne da Programação Orientada a Objetos — “um aluno é um tipo de usuário”, “um gato é um tipo de animal”. As classes-pai definem o comportamento comum, e as classes-filho o estendem e o especializam. O polimorfismo permite lidar com diferentes tipos de objetos por meio de uma interface unificada.
1. extends — Herança
<?php
// Parent class (base class)
class Animal {
public function __construct(
public string $name
) {}
public function speak(): string {
return "{$this->name} makes a sound";
}
public function sleep(): string {
return "{$this->name} is sleeping";
}
}
// Child class inherits from parent
class Dog extends Animal {
// Override the parent method
public function speak(): string {
return "{$this->name}: Woof!";
}
// Add a new method
public function fetch(): string {
return "{$this->name} went to fetch the ball";
}
}
class Cat extends Animal {
public function speak(): string {
return "{$this->name}: Meow~";
}
}
$dog = new Dog("Buddy");
echo $dog->speak(); // Buddy: Woof! (overridden method)
echo $dog->sleep(); // Buddy is sleeping (inherited method)
echo $dog->fetch(); // Buddy went to fetch the ball (new method)
$cat = new Cat("Luna");
echo $cat->speak(); // Luna: Meow~ (overridden method)
echo $cat->sleep(); // Luna is sleeping (inherited method)
?>
extends uma classe pai. A herança múltipla é possibilitada por meio de traits e interfaces (que serão abordados nas próximas aulas).
2. pai — Chamada de métodos do pai
Quando uma classe filha sobrescreve um método, mas você ainda deseja manter a lógica original da classe pai, use parent:::
<?php
class Vehicle {
public function __construct(
public string $brand,
public int $year
) {}
public function getInfo(): string {
return "{$this->year} {$this->brand}";
}
}
class ElectricCar extends Vehicle {
public function __construct(
string $brand,
int $year,
public int $batteryRange // Extra property for electric cars
) {
// Call the parent constructor
parent::__construct($brand, $year);
}
// Override and extend the parent method
public function getInfo(): string {
return parent::getInfo() . " Electric (range: {$this->batteryRange}km)";
}
}
$car = new ElectricCar("Tesla", 2026, 600);
echo $car->getInfo(); // 2026 Tesla Electric (range: 600km)
?>
3. final — Impedir herança/sobrescrita
<?php
class Template {
// Algorithm skeleton—child classes must not modify it
final public function render(): string {
$html = $this->header();
$html .= $this->body();
$html .= $this->footer();
return $html;
}
protected function header(): string {
return "<header>Default Header</header>";
}
protected function body(): string {
return "<main>Default Content</main>";
}
protected function footer(): string {
return "<footer>Default Footer</footer>";
}
}
// ✅ Child classes can override header/body/footer
class BlogTemplate extends Template {
protected function header(): string {
return "<header>Blog Title</header>";
}
// ❌ But they can't override render()—it's protected by final
// public function render(): string { ... }
}
?>
4. instanceof — Verificação de tipo
<?php
function makeSound(Animal $animal): string {
if ($animal instanceof Dog) {
return $animal->speak() . " (Good dog!)";
} elseif ($animal instanceof Cat) {
return $animal->speak() . " (So cute!)";
}
return $animal->speak();
}
echo makeSound(new Dog("Buddy")); // Buddy: Woof! (Good dog!)
echo makeSound(new Cat("Luna")); // Luna: Meow~ (So cute!)
?>
5. Classes abstratas
As classes abstratas não podem ser instanciadas diretamente — seu objetivo é definir “como uma subclasse deve ser”:
▶ Exemplo: Hierarquia de classes abstratas de formas
<?php
abstract class Shape {
public function __construct(
protected string $color = "Black"
) {}
// Abstract methods: subclasses must implement these
abstract public function area(): float;
abstract public function perimeter(): float;
// Regular method: subclasses can inherit or override
public function describe(): string {
return "A {$this->color} shape, area: " . round($this->area(), 2);
}
}
class Circle extends Shape {
public function __construct(
private float $radius,
string $color = "Black"
) {
parent::__construct($color);
}
public function area(): float {
return pi() * pow($this->radius, 2);
}
public function perimeter(): float {
return 2 * pi() * $this->radius;
}
}
class Rectangle extends Shape {
public function __construct(
private float $width,
private float $height,
string $color = "Black"
) {
parent::__construct($color);
}
public function area(): float {
return $this->width * $this->height;
}
public function perimeter(): float {
return 2 * ($this->width + $this->height);
}
}
// $s = new Shape("Red"); // ❌ Abstract classes can't be instantiated
$c = new Circle(5, "Red");
echo $c->describe(); // A Red shape, area: 78.54
$r = new Rectangle(4, 6, "Blue");
echo $r->describe(); // A Blue shape, area: 24
?>
6. Interfaces
Uma interface define um contrato sobre “o que você pode fazer”, sem definir “como você faz isso”:
<?php
interface Payable {
public function getAmount(): float;
public function pay(): string;
}
interface Refundable {
public function refund(): string;
}
// A class can implement multiple interfaces
class CreditCard implements Payable, Refundable {
public function __construct(
private string $cardNumber,
private float $amount
) {}
public function getAmount(): float {
return $this->amount;
}
public function pay(): string {
return "Credit card {$this->cardNumber} paid {$this->amount}";
}
public function refund(): string {
return "Refunded {$this->amount} to card {$this->cardNumber}";
}
}
class Crypto implements Payable {
public function __construct(
private float $amount
) {}
public function getAmount(): float {
return $this->amount;
}
public function pay(): string {
return "Crypto payment of {$this->amount}";
}
// Crypto doesn't support refunds—so it doesn't implement Refundable
}
?>
7. Polimorfismo na prática
A ideia central do polimorfismo: lidar com objetos de diferentes subclasses por meio de um tipo pai/interface unificado:
▶ Exemplo: Sistema de pagamento polimórfico
<?php
class PaymentProcessor {
/**
* Process payment with polymorphism—works regardless of payment method
*/
public function process(Payable $payment): void {
echo "[Payment] {$payment->pay()}<br>";
// Some payment methods support refunds
if ($payment instanceof Refundable) {
echo "[Refund Support] {$payment->refund()}<br>";
}
}
/**
* Batch settlement—since all implement Payable, we can handle them uniformly
*/
public function settle(array $payments): float {
$total = 0;
foreach ($payments as $payment) {
$total += $payment->getAmount();
echo $payment->pay() . "<br>";
}
echo "Total: {$total}<br>";
return $total;
}
}
$processor = new PaymentProcessor();
// Polymorphism—the caller doesn't know the specific payment method
$processor->settle([
new CreditCard("1234-5678", 199.00),
new Crypto(0.05),
new CreditCard("8765-4321", 59.99),
]);
?>
| Característica | classe abstrata | interface |
|---|---|---|
| Pode ter propriedades | ✅ | ❌ |
| Pode ter métodos implementados | ✅ | ❌ (No PHP 8+ pode ter métodos padrão) |
| Pode conter constantes | ✅ | ✅ |
| Herança múltipla | ❌ (herança única) | ✅ (múltiplas interfaces) |
| Usado para | Relações “é um” | Capacidades “pode fazer” |
❓ Perguntas Frequentes
P: Quando devo usar
abstract classem vez deinterface? R: Use uma classe abstrata quando as subclasses compartilharem propriedades ou lógica (por exemplo, Shape possui uma propriedade de cor). Use uma interface quando classes completamente diferentes precisarem de uma funcionalidade comum (pagamento, registro em log, serialização).
P: Por que o PHP não suporta herança múltipla? R: A herança múltipla causa o “problema do diamante” — quando duas classes pai têm métodos com o mesmo nome, a classe filha não sabe qual deles usar. O PHP substitui a herança múltipla por interfaces e traits.
P: Qual é o objetivo das classes e métodos
final? R: Evitar que a lógica crítica seja modificada. Usefinalem código essencial, como cálculos de pagamento ou autenticação, para garantir que as subclasses não possam sobrescrevê-lo, assegurando assim um comportamento consistente.
📖 Resumo
extendsherda todas as propriedades e métodos públicos/protegidos da classe paiparent::chama um método do pai que foi sobrescritofinalimpede que uma classe seja herdada ou que um método seja sobrescritoinstanceofverifica se um objeto é uma instância de uma determinada classe- Classes abstratas: definem um “modelo de família”, obrigando as subclasses a implementar métodos abstratos
- Interfaces: definam um “contrato de capacidade” — uma classe pode implementar várias interfaces
- Polimorfismo: operar sobre objetos de diferentes subclasses por meio de um tipo pai/interface unificado
📝 Exercícios
- Crie uma classe pai
Vehicle(marca/ano/getInfo) e, em seguida, crie as classes filhasCareMotorcycle. SobrescrevagetInfo()utilizandoparent::getInfo()para preservar a saída da classe pai. - Crie uma interface
Logger(log(string $message): void) e, em seguida, implemente duas classes:FileLogger(grava em um arquivo) eDatabaseLogger(exibe na tela). Use o polimorfismo para lidar com o registro de logs de maneira uniforme. - Crie uma classe abstrata
Employee(nome/salário + método abstratocalculateBonus()) e, em seguida, implemente as classes derivadasManagereDeveloper, cada uma com sua própria lógica de cálculo de bônus.



