Classes e objetos em PHP

1. Introdução à Programação Orientada a Objetos em PHP

A Programação Orientada a Objetos (POO) é um paradigma que organiza o código em torno de "classes" e "objetos". Uma classe é um modelo ou blueprint que define a estrutura e o comportamento de um tipo de dado. Um objeto é uma instância concreta dessa classe, com valores específicos para suas propriedades.

A principal diferença entre programação procedural e orientada a objetos está na organização. No paradigma procedural, funções e dados são separados. Na POO, dados (propriedades) e comportamentos (métodos) são agrupados em classes, promovendo maior coesão e reutilização.

O suporte a POO no PHP evoluiu significativamente:
- PHP 4: Suporte inicial, limitado e sem conceitos modernos.
- PHP 5: Introduziu modificadores de acesso, construtores/destrutores, interfaces e classes abstratas.
- PHP 7: Adicionou tipagem escalar, declaração de tipos de retorno e operador ??.
- PHP 8: Trouxe atributos, construtores com promoção de propriedades e tipos mistos.

2. Declarando e Instanciando Classes

A sintaxe básica de uma classe utiliza a palavra-chave class, seguida pelo nome e um bloco contendo propriedades e métodos.

<?php
class Carro {
    public string $marca;
    public string $modelo;
    public int $ano;

    public function exibirDetalhes(): string {
        return "{$this->marca} {$this->modelo} ({$this->ano})";
    }
}

$meuCarro = new Carro();
$meuCarro->marca = "Toyota";
$meuCarro->modelo = "Corolla";
$meuCarro->ano = 2022;
echo $meuCarro->exibirDetalhes(); // Toyota Corolla (2022)

A pseudo-variável $this refere-se ao objeto atual dentro de um método, permitindo acesso às propriedades e métodos da instância.

3. Propriedades e Métodos

Propriedades podem ser declaradas com tipos específicos (PHP 7.4+). Métodos podem ser públicos (acessíveis externamente) ou privados (acessíveis apenas dentro da classe).

<?php
class ContaBancaria {
    private float $saldo = 0;

    public function depositar(float $valor): void {
        if ($valor > 0) {
            $this->saldo += $valor;
        }
    }

    public function getSaldo(): float {
        return $this->saldo;
    }
}

$conta = new ContaBancaria();
$conta->depositar(500);
echo $conta->getSaldo(); // 500

Métodos e propriedades estáticas pertencem à classe, não a instâncias. São acessados com :: (operador de resolução de escopo).

<?php
class Configuracao {
    public static string $ambiente = "desenvolvimento";

    public static function getAmbiente(): string {
        return self::$ambiente;
    }
}

echo Configuracao::$ambiente; // desenvolvimento
echo Configuracao::getAmbiente(); // desenvolvimento

4. Construtores e Destrutores

O método __construct() é executado automaticamente ao criar um objeto. Permite inicializar propriedades com valores passados como argumentos.

<?php
class Usuario {
    public function __construct(
        public string $nome,
        public string $email
    ) {
        // Construtor com promoção de propriedades (PHP 8+)
        echo "Usuário {$this->nome} criado.\n";
    }

    public function __destruct() {
        echo "Usuário {$this->nome} destruído.\n";
    }
}

$usuario = new Usuario("Maria", "maria@exemplo.com");
// Saída: Usuário Maria criado.
// Ao final do script: Usuário Maria destruído.

O __destruct() é chamado quando o objeto é destruído (fim do script ou quando todas as referências são removidas). Útil para liberar recursos como conexões de banco de dados.

5. Modificadores de Acesso e Encapsulamento

Os modificadores de acesso controlam a visibilidade de propriedades e métodos:
- public: acessível de qualquer lugar.
- protected: acessível na classe e em classes filhas.
- private: acessível apenas na própria classe.

O encapsulamento protege os dados internos, expondo apenas o necessário através de getters e setters.

<?php
class Produto {
    private float $preco;

    public function setPreco(float $preco): void {
        if ($preco >= 0) {
            $this->preco = $preco;
        } else {
            throw new InvalidArgumentException("Preço não pode ser negativo.");
        }
    }

    public function getPreco(): float {
        return $this->preco;
    }
}

$produto = new Produto();
$produto->setPreco(49.90);
echo $produto->getPreco(); // 49.9

Benefícios do encapsulamento: validação de dados, segurança (impede acesso direto a propriedades sensíveis) e facilidade de manutenção (mudanças internas não afetam código externo).

6. Herança e Reutilização de Código

A herança permite que uma classe filha estenda uma classe pai, herdando suas propriedades e métodos. Usa-se extends.

<?php
class Animal {
    public string $nome;

    public function fazerSom(): string {
        return "Som genérico";
    }
}

class Cachorro extends Animal {
    public function fazerSom(): string {
        return "Au au";
    }
}

class Gato extends Animal {
    public function fazerSom(): string {
        return "Miau";
    }
}

$cachorro = new Cachorro();
$cachorro->nome = "Rex";
echo $cachorro->fazerSom(); // Au au

A sobrescrita de métodos permite que a classe filha substitua o comportamento do pai. O operador parent:: chama o método da classe pai.

Classes abstratas (abstract) não podem ser instanciadas diretamente. Servem como base para outras classes, definindo métodos abstratos que devem ser implementados.

<?php
abstract class Forma {
    abstract public function calcularArea(): float;
}

class Circulo extends Forma {
    public function __construct(private float $raio) {}

    public function calcularArea(): float {
        return pi() * $this->raio ** 2;
    }
}

7. Interfaces e Polimorfismo

Interfaces definem contratos que classes devem cumprir. Uma classe pode implementar múltiplas interfaces com implements.

<?php
interface Pagavel {
    public function processarPagamento(float $valor): bool;
}

interface Relatorio {
    public function gerarRecibo(): string;
}

class Boleto implements Pagavel, Relatorio {
    public function processarPagamento(float $valor): bool {
        // Lógica de pagamento
        return true;
    }

    public function gerarRecibo(): string {
        return "Recibo gerado.";
    }
}

Polimorfismo permite tratar objetos de diferentes classes de forma uniforme, desde que implementem a mesma interface.

<?php
function executarPagamento(Pagavel $pagamento, float $valor): void {
    if ($pagamento->processarPagamento($valor)) {
        echo "Pagamento realizado com sucesso.\n";
    }
}

$boleto = new Boleto();
executarPagamento($boleto, 150.00);

8. Traits e Composição de Comportamento

Traits permitem reutilizar código em múltiplas classes, resolvendo limitações da herança única. Usa-se use dentro da classe.

<?php
trait Logavel {
    public function log(string $mensagem): void {
        echo "[LOG] {$mensagem}\n";
    }
}

trait Notificavel {
    public function notificar(string $mensagem): void {
        echo "[NOTIFICAÇÃO] {$mensagem}\n";
    }
}

class Pedido {
    use Logavel, Notificavel;

    public function criar(): void {
        $this->log("Pedido criado.");
        $this->notificar("Pedido #123 criado com sucesso.");
    }
}

$pedido = new Pedido();
$pedido->criar();
// [LOG] Pedido criado.
// [NOTIFICAÇÃO] Pedido #123 criado com sucesso.

Se dois traits possuírem métodos com o mesmo nome, usamos insteadof para resolver conflitos e as para renomear.

<?php
trait A {
    public function saudacao(): string {
        return "Olá de A";
    }
}

trait B {
    public function saudacao(): string {
        return "Olá de B";
    }
}

class Saudacao {
    use A, B {
        A::saudacao insteadof B;
        B::saudacao as saudacaoB;
    }
}

$s = new Saudacao();
echo $s->saudacao(); // Olá de A
echo $s->saudacaoB(); // Olá de B

Diferenças práticas:
- Herança: Relação "é um" (ex: Cachorro é um Animal). Útil para comportamento compartilhado.
- Interface: Contrato "pode fazer" (ex: Pagável pode processar pagamento). Permite polimorfismo.
- Trait: Reutilização de implementação "tem um comportamento". Evita duplicação sem forçar hierarquia.

Conclusão

Classes e objetos em PHP formam a base da programação orientada a objetos, oferecendo ferramentas poderosas para organizar e reutilizar código. Desde a declaração básica até conceitos avançados como traits e polimorfismo, a POO permite construir sistemas modulares, seguros e fáceis de manter. Dominar esses conceitos é essencial para qualquer desenvolvedor PHP que deseje criar aplicações robustas e escaláveis.

Referências