0Pricing
PHP Academy · Lektion

DDD-Bausteine: Entities und Value Objects

Modellieren Sie die Domäne mit ausdrucksstarken Entities und unveränderlichen Value Objects.

DDD-Bausteine: Entities und Value Objects ist eine kostenlose PHP Academy-Lektion auf CoddyKit. Dies ist Lektion 1 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des PHP Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der PHP Academy-Kurs umfasst insgesamt 4 Lektionen.

Der taktische Kern

Die taktischen Muster des Domain-Driven Design geben Ihnen ein Vokabular, um Geschäftskonzepte im Code zu modellieren. Die beiden grundlegenden Bausteine sind Entities (Objekte, die durch ihre Identität über die Zeit definiert sind) und Value Objects (Objekte, die durch ihre Attribute definiert und als unveränderlich behandelt werden). Wenn Sie diesen Unterschied richtig erfassen, prägt er alles Weitere in Ihrer Domänenschicht.

Identität oder Wert

Eine Entität besitzt eine stabile Identität, die auch dann bestehen bleibt, wenn sich ihre Attribute ändern: Ein Customer ist auch nach einem Umzug derselbe Kunde. Ein Wertobjekt besitzt keine Identität; Zwei Wertobjekte mit gleichen Attributen sind austauschbar, etwa zwei 5-Dollar-Scheine. Fragen Sie sich: „Wenn sich jedes Feld ändert, handelt es sich dann noch um dasselbe Ding?“ Wenn ja, handelt es sich um eine Entität.

Ein Wertobjekt

Wertobjekte sind unveränderlich und selbstvalidierend. Die readonly-Eigenschaften von PHP 8.1 erzwingen Unveränderlichkeit; der Konstruktor schützt die Invarianten, sodass niemals eine ungültige Instanz entstehen kann.

<?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

Wertgleichheit

Wertobjekte werden anhand struktureller Gleichheit und nicht anhand ihrer Referenz verglichen. Stellen Sie eine explizite Methode equals() bereit, statt sich auf == zu verlassen, da der lockere Vergleich von PHP überraschende Regeln hat. Ein Money-Wertobjekt muss sowohl den Betrag als auch die Währung berücksichtigen.

<?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

Unveränderlichkeit und „with“-Methoden

Da Wertobjekte unveränderlich sind, bedeutet das „Ändern“ eines Wertobjekts, eine neue Instanz zurückzugeben. Methoden wie add() oder withAmount() verändern das Objekt niemals; sie erzeugen einen neuen Wert. Dadurch werden Aliasing-Fehler vermieden und Wertobjekte können innerhalb der Domäne bedenkenlos gemeinsam verwendet werden.

<?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;

Eine Entität

Eine Entität wird durch ihre Identität definiert, typischerweise durch eine von der Domäne erzeugte ID und nicht durch eine automatisch inkrementierte Datenbank-ID. Beim Vergleich werden die IDs verglichen. Ihre Attribute können sich durch verhaltensreiche Methoden ändern, die die Invarianten schützen.

<?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

Erzeugung der Identität

Erzeugen Sie die Identität bevorzugt in der Domäne, etwa als UUID, und zwar vor der Persistenz, statt auf die Datenbank zu warten. So können Sie eine vollständig gültige Entität im Speicher erstellen, sie über Aggregate hinweg referenzieren und ohne Datenbank testen. Die ID ist Teil des Modells und kein Artefakt der Speicherung.

Reiches Verhalten statt anämischer Daten

Ein häufiges Anti-Pattern ist das anämische Domänenmodell: Entitäten sind Sammlungen öffentlicher Getter und Setter, während die gesamte Logik in „Service“-Klassen steckt. DDD verlagert Verhalten in die Entität. $order->cancel() kapselt die Regeln für eine Stornierung, statt dass Aufrufer ein Statusfeld direkt ändern.

<?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

Wertobjekte überall

Ersetzen Sie Primitive Obsession durch Wertobjekte. Statt string $email, int $cents und string $currency überall weiterzureichen, kapseln Sie diese Werte in Email und Money. Vorteile:

  • Die Validierung erfolgt einmalig bei der Erstellung.
  • Domänenregeln wie der Abgleich von Währungen liegen bei den Daten.
  • Typsignaturen dokumentieren die Absicht und verhindern Verwechslungen.

Hinweis zum Persistenz-Mapping

Wertobjekte werden häufig auf eingebettete Spalten und nicht auf eigene Tabellen abgebildet (Doctrine #[Embeddable]). Entitäten werden auf Zeilen abgebildet, deren Schlüssel ihre Identität ist. Halten Sie Persistenzbelange aus den Domänenobjekten selbst heraus: Das Modell sollte nicht wissen, dass es in MySQL gespeichert wird. Ein ORM oder ein von Hand geschriebener Mapper übersetzt zwischen der ausdrucksstarken Domäne und der Datenbank.

Zusammengesetzte Wertobjekte

Wertobjekte lassen sich zusammensetzen. Ein Address bündelt mehrere primitive Werte zu einem zusammenhängenden Konzept mit eigener Gleichheit und Formatierung. Die Entität enthält dann einen einzelnen reichhaltigen Typ statt fünf loser Zeichenketten, und die Regeln für die Adresse liegen an einer Stelle.

<?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;

Schnelltest

Entität oder Wertobjekt?

Zusammenfassung

Sie haben die beiden grundlegenden DDD-Bausteine kennengelernt. Entitäten werden durch eine stabile Identität definiert, enthalten reiches Verhalten und schützen ihre Invarianten durch Methoden. Wertobjekte sind unveränderlich, selbstvalidierend und werden anhand der Gleichheit ihrer Attribute verglichen; sie ersetzen Primitive Obsession. Die korrekte Modellierung dieser Konzepte – mit Logik in den Objekten statt in anämischen Datensammlungen – bildet die Grundlage für Aggregate, Repositories und den Rest der Domänenschicht.

Häufig gestellte Fragen

Ist die Lektion „DDD-Bausteine: Entities und Value Objects“ kostenlos?

Ja — der vollständige Text von „DDD-Bausteine: Entities und Value Objects“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des PHP Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der PHP Academy-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „DDD-Bausteine: Entities und Value Objects“?

Modellieren Sie die Domäne mit ausdrucksstarken Entities und unveränderlichen Value Objects. Du übst PHP Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um PHP Academy zu starten?

Keine Vorkenntnisse erforderlich. PHP Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 1 von 4.

Wie lange dauert die Lektion „DDD-Bausteine: Entities und Value Objects“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser PHP Academy-Lektion Code schreiben und ausführen?

Ja. Jede PHP Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. DDD-Bausteine: Entities und Value Objects
  2. Aggregates, Repositories und Factories
  3. Domain Events und Domain Services
  4. Bounded Contexts und Context Mapping
← Zurück zu PHP Academy