Dominando Herança e Polimorfismo em PHP em Projetos Reais Já leu

Herança em PHP: Fundamentos e Prática Herança é um dos pilares da Programação Orientada a Objetos. Permite que uma classe filha herde atributos e métodos de uma classe pai, eliminando duplicação de código e criando hierarquias lógicas. Em PHP, usamos a palavra-chave para estabelecer essa relação. Note que usamos para atributos que a classe filha precisa acessar, e para chamar métodos da classe pai. Isso garante encapsulamento sem bloquear o acesso necessário. Visibilidade e Modificadores A escolha correta entre , e é fundamental. Use para membros que classes filhas devem acessar, para dados sensíveis que nunca mudarão, e apenas quando necessário expor a interface. Polimorfismo: Múltiplas Formas, Uma Interface Polimorfismo permite que objetos de diferentes classes respondam ao mesmo método de formas distintas. É a capacidade de uma classe filha sobrescrever (override) métodos da classe pai, mantendo a mesma assinatura. Aqui usamos uma classe com um método , forçando que subclasses implementem . Cada animal responde diferentemente ao mesmo método.

Herança em PHP: Fundamentos e Prática

Herança é um dos pilares da Programação Orientada a Objetos. Permite que uma classe filha herde atributos e métodos de uma classe pai, eliminando duplicação de código e criando hierarquias lógicas. Em PHP, usamos a palavra-chave extends para estabelecer essa relação.

class Veiculo {
    protected $marca;
    protected $velocidade = 0;

    public function __construct($marca) {
        $this->marca = $marca;
    }

    public function acelerar() {
        $this->velocidade += 10;
        return "Acelerou para {$this->velocidade} km/h";
    }

    public function getMarca() {
        return $this->marca;
    }
}

class Carro extends Veiculo {
    private $portas;

    public function __construct($marca, $portas) {
        parent::__construct($marca);
        $this->portas = $portas;
    }

    public function abrirBagagem() {
        return "Bagagem aberta no {$this->marca}";
    }
}

$carro = new Carro("Toyota", 4);
echo $carro->acelerar();        // Acelerou para 10 km/h
echo $carro->abrirBagagem();    // Bagagem aberta no Toyota

Note que usamos protected para atributos que a classe filha precisa acessar, e parent:: para chamar métodos da classe pai. Isso garante encapsulamento sem bloquear o acesso necessário.

Visibilidade e Modificadores

A escolha correta entre public, protected e private é fundamental. Use protected para membros que classes filhas devem acessar, private para dados sensíveis que nunca mudarão, e public apenas quando necessário expor a interface.

Polimorfismo: Múltiplas Formas, Uma Interface

Polimorfismo permite que objetos de diferentes classes respondam ao mesmo método de formas distintas. É a capacidade de uma classe filha sobrescrever (override) métodos da classe pai, mantendo a mesma assinatura.

abstract class Animal {
    protected $nome;

    public function __construct($nome) {
        $this->nome = $nome;
    }

    abstract public function fazer_som();

    public function apresentar() {
        return "Sou o {$this->nome}";
    }
}

class Cachorro extends Animal {
    public function fazer_som() {
        return "{$this->nome} faz: Au au!";
    }
}

class Gato extends Animal {
    public function fazer_som() {
        return "{$this->nome} faz: Miau!";
    }
}

$animais = [
    new Cachorro("Rex"),
    new Gato("Félix")
];

foreach ($animais as $animal) {
    echo $animal->fazer_som() . "\n";
    // Rex faz: Au au!
    // Félix faz: Miau!
}

Aqui usamos uma classe abstract com um método abstract, forçando que subclasses implementem fazer_som(). Cada animal responde diferentemente ao mesmo método. Isso é polimorfismo em ação.

Tipagem e Type Hints

PHP 7+ permite definir tipos de retorno e parâmetros. Combine isso com polimorfismo para código mais robusto:

interface Voo {
    public function decolar(): string;
    public function pousar(): string;
}

class Aviao implements Voo {
    public function decolar(): string {
        return "Avião decolando...";
    }

    public function pousar(): string {
        return "Avião pousando...";
    }
}

function executarVoo(Voo $veiculo): void {
    echo $veiculo->decolar() . "\n";
    echo $veiculo->pousar() . "\n";
}

executarVoo(new Aviao());

Usando interface e type hints, garantimos que qualquer classe que implemente Voo funcionará com executarVoo(). Isso é polimorfismo paramétrico.

Casos Práticos: Quando Usar

Herança vs. Composição

Nem sempre herança é a melhor solução. Prefira composição quando a relação não é claramente "é um(a)":

// ❌ Evite
class Carro extends Motor { }

// ✅ Prefira
class Carro {
    private $motor;

    public function __construct(Motor $motor) {
        $this->motor = $motor;
    }

    public function ligar() {
        return $this->motor->iniciar();
    }
}

Use herança para relações "é um(a)" (Carro é Veiculo) e composição para relações "tem um(a)" (Carro tem Motor).

Exemplo Real: Sistema de Pagamento

abstract class Pagamento {
    protected $valor;
    protected $status = 'pendente';

    public function __construct($valor) {
        $this->valor = $valor;
    }

    abstract public function processar(): bool;

    public function getStatus(): string {
        return $this->status;
    }
}

class PagamentoCartao extends Pagamento {
    private $numero;

    public function __construct($valor, $numero) {
        parent::__construct($valor);
        $this->numero = $numero;
    }

    public function processar(): bool {
        // Simula validação
        if (strlen($this->numero) === 16) {
            $this->status = 'aprovado';
            return true;
        }
        $this->status = 'rejeitado';
        return false;
    }
}

class PagamentoPixel extends Pagamento {
    public function processar(): bool {
        $this->status = 'aprovado';
        return true;
    }
}

function realizarVenda(Pagamento $metodo): void {
    if ($metodo->processar()) {
        echo "Venda finalizada - Status: " . $metodo->getStatus();
    } else {
        echo "Falha na venda - Status: " . $metodo->getStatus();
    }
}

realizarVenda(new PagamentoCartao(150, '1234567890123456'));
realizarVenda(new PagamentoPixel(200));

Este exemplo mostra como polimorfismo permite adicionar novos métodos de pagamento sem modificar realizarVenda(). Respeita o princípio Open/Closed.

Conclusão

Herança e polimorfismo são ferramentas poderosas quando usadas corretamente. Primeiro aprendizado: use herança para relações hierárquicas reais, não para reutilização de código superficial. Segundo: polimorfismo permite escrever código flexível e extensível que funciona com múltiplas classes através da mesma interface. Terceiro: combine com interfaces e classes abstratas para criar contratos claros e manuteníveis. Dominar esses conceitos elevará significativamente a qualidade da sua arquitetura de software.

Referências


Artigos relacionados