0Pricing
PHP Academy · Aula

Blocos básicos de DDD: entidades e objetos de valor

Modele o domínio com entidades ricas e objetos de valor imutáveis.

Blocos básicos de DDD: entidades e objetos de valor é uma aula grátis de PHP Academy no CoddyKit. Esta é a aula 1 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de PHP Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de PHP Academy inclui 4 aulas no total.

O núcleo tático

Os padrões táticos do Design Orientado a Domínio fornecem um vocabulário para modelar conceitos de negócio no código. Os dois blocos fundamentais são Entidades (objetos definidos pela identidade ao longo do tempo) e Objetos de Valor (objetos definidos por seus atributos e tratados como imutáveis). Acertar essa distinção molda todo o restante da camada de domínio.

Identidade versus valor

Uma entidade tem uma identidade estável que persiste mesmo quando seus atributos mudam: um Customer continua sendo o mesmo cliente depois de mudar de casa. Um objeto de valor não tem identidade; dois objetos de valor com atributos iguais são intercambiáveis, como duas notas de 5 dólares. Pergunte: "se todos os campos mudarem, ainda será a mesma coisa?" Se sim, trata-se de uma entidade.

Um objeto de valor

Os objetos de valor são imutáveis e autovalidáveis. As propriedades readonly do PHP 8.1 impõem a imutabilidade; o construtor protege as invariantes para que uma instância inválida jamais possa existir.

<?php
final class Email {
    public function __construct(public readonly string $value) {
        if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
            throw new InvalidArgumentException("Invalid email: $value");
        }
    }
    public function equals(Email $other): bool {
        return strtolower($this->value) === strtolower($other->value);
    }
}
$a = new Email('Jane@Example.com');
var_dump($a->equals(new Email('jane@example.com'))); // true

Igualdade por valor

Os objetos de valor são comparados por igualdade estrutural, não por referência. Forneça um método explícito equals() em vez de depender de ==, pois a comparação flexível do PHP tem regras surpreendentes. Um objeto de valor Money deve considerar tanto o valor quanto a moeda.

<?php
final class Money {
    public function __construct(
        public readonly int $cents,
        public readonly string $currency
    ) {}
    public function equals(Money $o): bool {
        return $this->cents === $o->cents && $this->currency === $o->currency;
    }
    public function add(Money $o): self {
        if ($this->currency !== $o->currency) {
            throw new DomainException('Currency mismatch');
        }
        return new self($this->cents + $o->cents, $this->currency);
    }
}
$sum = (new Money(500, 'USD'))->add(new Money(250, 'USD'));
echo $sum->cents, PHP_EOL; // 750

Imutabilidade e métodos de cópia

Como os objetos de valor são imutáveis, "alterar" um deles significa retornar uma nova instância. Métodos como add() ou withAmount() nunca modificam o objeto; eles produzem um novo valor. Isso elimina erros de aliasing e torna os objetos de valor seguros para serem compartilhados livremente em todo o domínio.

<?php
final class DateRange {
    public function __construct(
        public readonly DateTimeImmutable $start,
        public readonly DateTimeImmutable $end
    ) {
        if ($end < $start) { throw new InvalidArgumentException('end before start'); }
    }
    public function withEnd(DateTimeImmutable $end): self {
        return new self($this->start, $end);
    }
}
$r = new DateRange(new DateTimeImmutable('2026-01-01'), new DateTimeImmutable('2026-01-10'));
$r2 = $r->withEnd(new DateTimeImmutable('2026-02-01'));
echo $r->end->format('Y-m-d'), ' / ', $r2->end->format('Y-m-d'), PHP_EOL;

Uma entidade

Uma entidade é definida pela identidade, normalmente um identificador gerado pelo domínio, e não por um incremento automático do banco de dados. A igualdade compara os identificadores. Seus atributos podem mudar por meio de métodos ricos em comportamento que protegem as invariantes.

<?php
final class Customer {
    private Email $email;
    public function __construct(
        public readonly string $id,
        Email $email
    ) { $this->email = $email; }

    public function changeEmail(Email $new): void { $this->email = $new; }
    public function email(): Email { return $this->email; }
    public function sameIdentityAs(Customer $o): bool { return $this->id === $o->id; }
}
$c = new Customer('cus_1', new Email('a@b.com'));
$c->changeEmail(new Email('c@d.com'));
echo $c->email()->value, PHP_EOL; // c@d.com

Geração de identidade

Prefira gerar a identidade no domínio (por exemplo, um UUID) antes da persistência, em vez de esperar pelo banco de dados. Isso permite construir uma entidade totalmente válida em memória, referenciá-la entre agregados e testá-la sem um banco de dados. O identificador faz parte do modelo, não é um artefato de armazenamento.

Comportamento rico, não dados anêmicos

Um antipadrão comum é o modelo de domínio anêmico: as entidades são conjuntos de getters/setters públicos, enquanto toda a lógica fica em classes de "serviço". O DDD coloca o comportamento dentro da entidade. $order->cancel() encapsula as regras do cancelamento, em vez de permitir que os chamadores alterem diretamente um campo de status.

<?php
final class Order {
    private string $status = 'open';
    public function __construct(public readonly string $id) {}
    public function cancel(): void {
        if ($this->status === 'shipped') {
            throw new DomainException('Cannot cancel a shipped order');
        }
        $this->status = 'cancelled';
    }
    public function status(): string { return $this->status; }
}
$o = new Order('o1');
$o->cancel();
echo $o->status(), PHP_EOL; // cancelled

Objetos de valor em toda parte

Substitua a obsessão por tipos primitivos por objetos de valor. Em vez de passar string $email, int $cents e string $currency por toda parte, envolva-os em Email e Money. Benefícios:

  • A validação acontece uma vez, na construção.
  • As regras do domínio (correspondência de moedas) ficam junto dos dados.
  • As assinaturas de tipo documentam a intenção e evitam confusões.

Observação sobre mapeamento da persistência

Os objetos de valor geralmente são mapeados para colunas incorporadas, em vez de tabelas próprias (Doctrine #[Embeddable]). As entidades são mapeadas para linhas identificadas por sua identidade. Mantenha as preocupações de persistência fora dos próprios objetos de domínio: o modelo não deve saber que está armazenado no MySQL. Um mapeador objeto-relacional ou um mapeador escrito manualmente traduz entre o domínio rico e o banco de dados.

Objetos de valor compostos

Os objetos de valor podem ser compostos. Um Address agrega vários tipos primitivos em um conceito coeso, com sua própria igualdade e formatação. Assim, a entidade mantém um único tipo rico em vez de cinco textos soltos, e as regras do endereço ficam em um só lugar.

<?php
final class Address {
    public function __construct(
        public readonly string $street,
        public readonly string $city,
        public readonly string $postcode
    ) {
        if ($postcode === '') { throw new InvalidArgumentException('postcode required'); }
    }
    public function equals(Address $o): bool {
        return $this->street === $o->street
            && $this->city === $o->city
            && $this->postcode === $o->postcode;
    }
    public function oneLine(): string {
        return "{$this->street}, {$this->city} {$this->postcode}";
    }
}
echo (new Address('1 Main St', 'Ankara', '06000'))->oneLine(), PHP_EOL;

Verificação rápida

Entidade ou objeto de valor?

Recapitulação

Você aprendeu os dois blocos fundamentais do DDD. As entidades são definidas por uma identidade estável, carregam um comportamento rico e protegem suas invariantes por meio de métodos. Os objetos de valor são imutáveis, autovalidáveis e comparados pela igualdade de atributos, substituindo a obsessão por tipos primitivos. Modelá-los corretamente, mantendo a lógica dentro dos objetos em vez de conjuntos de dados anêmicos, é a base para agregados, repositórios e o restante da camada de domínio.

Perguntas Frequentes

A aula “Blocos básicos de DDD: entidades e objetos de valor” é grátis?

Sim — o texto completo de “Blocos básicos de DDD: entidades e objetos de valor” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de PHP Academy, atualize para CoddyKit PRO. O curso de PHP Academy inclui 4 aulas no total.

O que vou aprender em “Blocos básicos de DDD: entidades e objetos de valor”?

Modele o domínio com entidades ricas e objetos de valor imutáveis. Você pratica PHP Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar PHP Academy?

Nenhuma experiência prévia é necessária. PHP Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 1 de 4.

Quanto tempo leva a aula “Blocos básicos de DDD: entidades e objetos de valor”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de PHP Academy?

Sim. Cada aula de PHP Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Blocos básicos de DDD: entidades e objetos de valor
  2. Agregados, repositórios e fábricas
  3. Eventos e serviços de domínio
  4. Contextos delimitados e mapeamento de contextos
← Voltar para PHP Academy