Herança, Interfaces e Métodos Mágicos

Nesta aula, aprofundaremos a Programação Orientada a Objetos (POO) em PHP, mostrando como a herança permite criar hierarquias de classes, como interfaces garantem a consistência do código e como os métodos mágicos oferecem um controle poderoso sobre o comportamento dos objetos.

Herança: A Reutilização Inteligente do Código

A herança é um dos pilares da POO. Ela nos permite criar uma nova classe (classe filha) que reutiliza atributos e métodos de uma classe existente (classe pai). A classe filha pode, então, adicionar suas próprias funcionalidades ou modificar as da classe pai. Isso promove a reutilização de código e a organização de classes em uma hierarquia lógica.

Exemplo: Vamos criar uma hierarquia de veículos. A classe Veiculo será a classe pai, e a classe Carro será a classe filha.

<?php

// Classe Pai (superclasse)
class Veiculo {
    protected $velocidade = 0;

    public function acelerar($valor) {
        $this->velocidade += $valor;
        echo "Acelerando... Velocidade atual: " . $this->velocidade . " km/h.<br>";
    }

    public function frear($valor) {
        $this->velocidade -= $valor;
        if ($this->velocidade < 0) {
            $this->velocidade = 0;
        }
        echo "Freando... Velocidade atual: " . $this->velocidade . " km/h.<br>";
    }
}

// Classe Filha (subclasse) que herda de Veiculo
class Carro extends Veiculo {
    public $portas;

    public function __construct($portas) {
        $this->portas = $portas;
        echo "Um novo carro foi criado com " . $this->portas . " portas.<br>";
    }

    // O método acelerar() da classe Veiculo é reutilizado
    // O método frear() da classe Veiculo também é reutilizado
}

// Criando uma instância da classe Carro
$meuCarro = new Carro(4);
$meuCarro->acelerar(50);
$meuCarro->frear(20);

?>

A palavra-chave extends indica que a classe Carro herda de Veiculo.

A propriedade $velocidade é protected, o que significa que ela é acessível dentro da classe Veiculo e por suas classes filhas.

O método __construct é um método mágico (veremos mais sobre eles abaixo). Ele é chamado automaticamente quando um novo objeto é criado.

Interfaces: Padronização e Contratos

Uma interface é como um “contrato”. Ela define um conjunto de métodos que uma classe deve implementar. Uma classe que implementa uma interface deve obrigatoriamente fornecer a implementação para todos os métodos definidos na interface. Isso garante que diferentes classes, mesmo que sem herança, tenham a mesma “assinatura” de métodos, facilitando a interação e o polimorfismo.

Exemplo: Vamos criar uma interface Ajustavel para veículos que podem ter sua velocidade ajustada.


<?php

// Definindo a interface
interface Ajustavel {
    public function aumentarVelocidade($valor);
    public function diminuirVelocidade($valor);
}

// Classe que implementa a interface
class Moto extends Veiculo implements Ajustavel {
    public function aumentarVelocidade($valor) {
        $this->acelerar($valor);
    }

    public function diminuirVelocidade($valor) {
        $this->frear($valor);
    }
}

// Criando uma instância da classe Moto
$minhaMoto = new Moto();
$minhaMoto->aumentarVelocidade(80);
$minhaMoto->diminuirVelocidade(30);

?>

A palavra-chave implements indica que a classe Moto está implementando a interface Ajustavel.

A classe Moto deve obrigatoriamente ter os métodos aumentarVelocidade() e diminuirVelocidade(), com a mesma assinatura da interface.

Isso permite que Moto e outras classes que implementarem Ajustavel possam ser tratadas de forma uniforme.

Métodos Mágicos: Comportamentos Especiais

Métodos mágicos são métodos especiais que começam com dois underscores (__). Eles são acionados automaticamente pelo PHP em determinadas situações, permitindo que você controle o comportamento dos objetos.

Os mais comuns são:

__construct(): Chamado quando um objeto é criado. Perfeito para inicializar propriedades.

__destruct(): Chamado quando um objeto é destruído (por exemplo, quando o script termina). Útil para liberar recursos.

__get($propriedade): Chamado quando você tenta acessar uma propriedade inacessível (ex: private).

__set($propriedade, $valor): Chamado quando você tenta definir o valor de uma propriedade inacessível.

__call($metodo, $argumentos): Chamado quando você tenta chamar um método que não existe.

__toString(): Chamado quando um objeto é tratado como uma string (ex: echo $objeto;). Deve retornar uma string.

Exemplo: Usando __get, __set e __toString


<?php

class Usuario {
    private $nome;
    private $email;

    public function __set($propriedade, $valor) {
        if (property_exists($this, $propriedade)) {
            $this->$propriedade = $valor;
        } else {
            echo "Propriedade '{$propriedade}' não existe.<br>";
        }
    }

    public function __get($propriedade) {
        if (property_exists($this, $propriedade)) {
            return $this->$propriedade;
        }
        return null;
    }

    public function __toString() {
        return "Nome: {$this->nome}, Email: {$this->email}";
    }
}

$usuario = new Usuario();

// Usando o método mágico __set
$usuario->nome = "João";
$usuario->email = "joao@exemplo.com";

// Usando o método mágico __get
echo "Nome do usuário: " . $usuario->nome . "<br>"; // Saída: Nome do usuário: João

// Usando o método mágico __toString
echo "Detalhes do usuário: " . $usuario . "<br>"; // Saída: Detalhes do usuário: Nome: João, Email: joao@exemplo.com

?>

Com __set, podemos definir uma lógica para atribuir valores às propriedades privadas sem precisar de um setter para cada uma.

Com __get, podemos buscar o valor das propriedades privadas.

Com __toString, podemos controlar o que acontece quando o objeto é impresso.