PHP

Orientação a Objetos: Fundamentos Já leu

10 min de leitura

Orientação a Objetos: Fundamentos
Orientação a Objetos é o paradigma que organiza o código em torno de entidades — objetos — que combinam dados e comporta

Orientação a Objetos é o paradigma que organiza o código em torno de entidades — objetos — que combinam dados e comportamento em uma única unidade. É o modelo dominante no desenvolvimento PHP profissional: frameworks como Laravel, Symfony e Doctrine são construídos inteiramente sobre OOP.

Neste artigo cobrimos os fundamentos: classes, objetos, propriedades, métodos, construtores, visibilidade e os conceitos de encapsulamento que tornam o código orientado a objetos mais seguro e expressivo do que o código procedural.


O que é uma classe

Uma classe é um molde — ela descreve como um objeto deve ser. Um objeto é uma instância desse molde — um exemplar concreto criado a partir dele:

<?php
declare(strict_types=1);

// Classe — o molde
class Produto
{
    // Propriedades — os dados que cada objeto carrega
    public string $nome;
    public float  $preco;
    public int    $estoque;
}

// Objeto — uma instância criada a partir do molde
$teclado = new Produto();
$teclado->nome    = "Teclado Mecânico";
$teclado->preco   = 350.0;
$teclado->estoque = 15;

$mouse = new Produto(); // outro objeto, independente do $teclado
$mouse->nome    = "Mouse Gamer";
$mouse->preco   = 180.0;
$mouse->estoque = 42;

echo $teclado->nome;  // Teclado Mecânico
echo $mouse->preco;   // 180.0

// Cada objeto tem seus próprios dados — são independentes
$teclado->preco = 320.0; // muda apenas o $teclado
echo $mouse->preco;      // 180.0 — não foi afetado

Construtor — inicializando objetos

O construtor é um método especial chamado automaticamente quando um objeto é criado com new. Ele garante que o objeto começa em um estado válido:

<?php
declare(strict_types=1);

class Produto
{
    public string $nome;
    public float  $preco;
    public int    $estoque;

    // __construct é chamado automaticamente pelo new
    public function __construct(string $nome, float $preco, int $estoque = 0)
    {
        // Validação no construtor — objeto nasce válido ou não nasce
        if ($preco < 0) {
            throw new InvalidArgumentException("Preço não pode ser negativo.");
        }

        $this->nome    = $nome;
        $this->preco   = $preco;
        $this->estoque = $estoque;
    }
}

// Agora o new exige os dados obrigatórios
$teclado = new Produto("Teclado Mecânico", 350.0, 15);
echo $teclado->nome; // Teclado Mecânico

// Tentativa de criar produto inválido — lança exceção
// $invalido = new Produto("Teste", -10.0); // InvalidArgumentException

Promoção de propriedades no construtor (PHP 8)

O PHP 8 introduziu uma sintaxe muito mais compacta que declara e atribui propriedades diretamente nos parâmetros do construtor:

<?php
declare(strict_types=1);

class Produto
{
    // PHP 8: public/protected/private no parâmetro declara e atribui
    // automaticamente a propriedade — elimina muito código repetitivo
    public function __construct(
        public readonly string $nome,    // readonly — não pode ser modificado após o construtor
        public float           $preco,
        public int             $estoque = 0,
    ) {
        if ($this->preco < 0) {
            throw new InvalidArgumentException("Preço não pode ser negativo.");
        }
    }
}

$p = new Produto("Monitor 4K", 2500.0, 5);
echo $p->nome;    // Monitor 4K
echo $p->preco;   // 2500.0

// $p->nome = "Outro"; // Error: Cannot modify readonly property

Métodos — o comportamento do objeto

Métodos são funções definidas dentro de uma classe. Eles operam sobre os dados do próprio objeto através de $this:

<?php
declare(strict_types=1);

class Produto
{
    public function __construct(
        public readonly string $nome,
        public float $preco,
        public int   $estoque = 0,
    ) {}

    // Método de consulta — retorna informação
    public function estaDisponivel(): bool
    {
        return $this->estoque > 0;
    }

    // Método de ação — modifica o estado do objeto
    public function adicionarEstoque(int $quantidade): void
    {
        if ($quantidade <= 0) {
            throw new InvalidArgumentException("Quantidade deve ser positiva.");
        }
        $this->estoque += $quantidade;
    }

    public function vender(int $quantidade): void
    {
        if ($quantidade > $this->estoque) {
            throw new RuntimeException("Estoque insuficiente.");
        }
        $this->estoque -= $quantidade;
    }

    // Método de formatação — representação legível
    public function resumo(): string
    {
        $status = $this->estaDisponivel() ? "disponível" : "esgotado";
        return "{$this->nome} — R$ {$this->preco} ({$status})";
    }
}

$monitor = new Produto("Monitor 4K", 2500.0, 3);

echo $monitor->resumo();           // Monitor 4K — R$ 2500.0 (disponível)
$monitor->vender(3);
echo $monitor->estaDisponivel();   // false (bool)
echo $monitor->resumo();           // Monitor 4K — R$ 2500.0 (esgotado)

Visibilidade: public, protected, private

A visibilidade controla quem pode acessar propriedades e métodos. É o mecanismo central do encapsulamento:

<?php
declare(strict_types=1);

class ContaBancaria
{
    // private — acessível apenas dentro desta classe
    private float $saldo;
    private array $historico = [];

    // public — acessível de qualquer lugar
    public string $titular;

    public function __construct(string $titular, float $depositoInicial = 0.0)
    {
        $this->titular = $titular;
        $this->saldo   = 0.0;

        if ($depositoInicial > 0) {
            $this->depositar($depositoInicial);
        }
    }

    public function depositar(float $valor): void
    {
        $this->validarValor($valor);
        $this->saldo += $valor;
        $this->registrar("Depósito", $valor);
    }

    public function sacar(float $valor): void
    {
        $this->validarValor($valor);

        if ($valor > $this->saldo) {
            throw new RuntimeException("Saldo insuficiente.");
        }

        $this->saldo -= $valor;
        $this->registrar("Saque", $valor);
    }

    // Método getter — acesso controlado ao saldo
    public function getSaldo(): float
    {
        return $this->saldo;
    }

    public function getHistorico(): array
    {
        return $this->historico;
    }

    // private — usado internamente, não exposto ao mundo externo
    private function validarValor(float $valor): void
    {
        if ($valor <= 0) {
            throw new InvalidArgumentException("Valor deve ser positivo.");
        }
    }

    private function registrar(string $tipo, float $valor): void
    {
        $this->historico[] = [
            "tipo"  => $tipo,
            "valor" => $valor,
            "data"  => date("d/m/Y H:i"),
        ];
    }
}

$conta = new ContaBancaria("Ana Silva", 1000.0);
$conta->depositar(500.0);
$conta->sacar(200.0);

echo $conta->getSaldo(); // 1300.0

// $conta->saldo = 99999; // Error: Cannot access private property
// $conta->validarValor(-10); // Error: Cannot call private method

Propriedades e métodos estáticos

Membros estáticos pertencem à classe, não a uma instância específica. Eles existem independentemente de qualquer objeto criado:

<?php
declare(strict_types=1);

class Configuracao
{
    // static — existe na classe, não no objeto
    private static array $valores = [];
    private static int   $chamadas = 0;

    // Método estático — chamado na classe, não no objeto
    public static function definir(string $chave, mixed $valor): void
    {
        self::$valores[$chave] = $valor;
    }

    public static function obter(string $chave, mixed $padrao = null): mixed
    {
        self::$chamadas++;
        return self::$valores[$chave] ?? $padrao;
    }

    public static function totalChamadas(): int
    {
        return self::$chamadas;
    }
}

// Chamada com :: (double colon / paamayim nekudotayim)
// Não precisa criar objeto
Configuracao::definir("app.nome", "Minha Aplicação");
Configuracao::definir("app.versao", "1.0.0");

echo Configuracao::obter("app.nome");    // Minha Aplicação
echo Configuracao::obter("app.debug", false); // false — padrão
echo Configuracao::totalChamadas();     // 2

// Constante de classe — imutável, compartilhada entre todas as instâncias
class Moeda
{
    const BRL = "BRL";
    const USD = "USD";
    const EUR = "EUR";

    // PHP 8.3: constante tipada
    // const string SIMBOLO_BRL = "R$";
}

echo Moeda::BRL; // BRL

Encapsulamento — o princípio por trás da visibilidade

O encapsulamento não é apenas esconder dados — é garantir que o objeto sempre esteja em um estado válido e que mudanças de estado passem por regras de negócio:

<?php
declare(strict_types=1);

// ✗ Sem encapsulamento — o objeto pode ser corrompido
class PedidoAberto
{
    public string $status = "pendente";
    public float  $total  = 0.0;
    public array  $itens  = [];
}

$pedido = new PedidoAberto();
$pedido->status = "cancelado"; // permitido mesmo sem itens
$pedido->total  = -500.0;      // total negativo — estado inválido!

// ✓ Com encapsulamento — o objeto protege seu próprio estado
class Pedido
{
    private string $status = "pendente";
    private float  $total  = 0.0;
    private array  $itens  = [];

    // Transição de estado passa por validação
    public function cancelar(): void
    {
        if ($this->status === "entregue") {
            throw new RuntimeException("Pedido entregue não pode ser cancelado.");
        }
        $this->status = "cancelado";
    }

    public function adicionarItem(string $nome, float $preco, int $qtd): void
    {
        if ($this->status !== "pendente") {
            throw new RuntimeException("Só é possível adicionar itens a pedidos pendentes.");
        }

        $this->itens[] = ["nome" => $nome, "preco" => $preco, "qtd" => $qtd];
        $this->total  += $preco * $qtd;
    }

    public function getStatus(): string { return $this->status; }
    public function getTotal(): float   { return $this->total; }
    public function getItens(): array   { return $this->itens; }
}

O método mágico __toString

O PHP tem vários métodos mágicos — métodos com nomes especiais que são chamados em situações específicas. O __toString é invocado quando o objeto é usado em contexto de string:

<?php
declare(strict_types=1);

class Produto
{
    public function __construct(
        public readonly string $nome,
        public float $preco,
    ) {}

    // Chamado quando o objeto é tratado como string
    public function __toString(): string
    {
        return "{$this->nome} (R$ " . number_format($this->preco, 2, ',', '.') . ")";
    }
}

$p = new Produto("Teclado", 350.0);
echo $p;                // Teclado (R$ 350,00) — __toString chamado automaticamente
echo "Produto: $p";     // Produto: Teclado (R$ 350,00) — interpolação também chama
$s = (string) $p;       // cast explícito também chama __toString

Boas práticas em OOP

Nomeie classes com substantivos, métodos com verbos. Pedido, Usuario, Produto — não GerenciadorDePedido. Métodos: calcularTotal(), validarEmail(), cancelar().

Prefira readonly em propriedades imutáveis. Se uma propriedade não deve mudar após a criação, declare-a readonly. O PHP 8.1 introduziu readonly para propriedades individuais; o PHP 8.2 para classes inteiras.

Nunca deixe objetos em estado inválido. O construtor deve validar os dados e lançar exceção se os dados não permitem criar um objeto válido. É melhor falhar na criação do que ter um objeto corrompido rodando pelo sistema.

Limite o número de dependências públicas. Quanto menos o código externo precisar conhecer sobre o interior de uma classe, mais fácil é mudar essa classe no futuro.


Resumo

Conceito O que aprendemos
class Define o molde — estrutura e comportamento
new Cria uma instância (objeto) da classe
$this Referência ao objeto atual dentro dos métodos
__construct Chamado automaticamente pelo new
Promoção de propriedades Declara e atribui no construtor — PHP 8
readonly Propriedade que não pode ser modificada após o construtor
public Acessível de qualquer lugar
private Acessível apenas dentro da própria classe
protected Acessível na classe e em subclasses (veremos em herança)
static Pertence à classe, não à instância — acesso com ::
const Constante de classe — imutável, compartilhada
__toString Método mágico para representação em string
Encapsulamento Proteger estado interno — objeto sempre válido

Referências e leituras para aprofundar

Comentários

Mais em PHP

Configurando o Ambiente de Desenvolvimento
Configurando o Ambiente de Desenvolvimento

Antes de escrever qualquer programa, voc&ecirc; precisa de um ambiente onde o...

Exceções Avançadas
Exceções Avançadas

Tratamento de erros &eacute; onde c&oacute;digo bom se separa de c&oacute;dig...

O que é PHP e por que ele ainda importa
O que é PHP e por que ele ainda importa

Quando voc&ecirc; acessa um site, preenche um formul&aacute;rio, faz login em...