0Pricing
PHP Academy · Pelajaran

Blok Bangunan DDD: Entitas dan Objek Nilai

Modelkan domain dengan entitas kaya perilaku dan objek nilai yang tidak dapat diubah.

Blok Bangunan DDD: Entitas dan Objek Nilai adalah pelajaran PHP Academy gratis di CoddyKit. Ini adalah pelajaran 1 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar PHP Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus PHP Academy mencakup 4 pelajaran total.

Inti taktis

Pola taktis Perancangan Berbasis Domain memberi Anda kosakata untuk memodelkan konsep bisnis dalam kode. Dua blok pembangun dasarnya adalah Entitas (objek yang ditentukan oleh identitas sepanjang waktu) dan Objek Nilai (objek yang ditentukan oleh atributnya dan diperlakukan sebagai objek yang tidak dapat diubah). Mendapatkan pembedaan ini dengan tepat akan membentuk segala sesuatu lainnya di lapisan domain Anda.

Identitas vs nilai

Entitas memiliki identitas stabil yang tetap bertahan meskipun atributnya berubah: sebuah Customer tetap merupakan pelanggan yang sama setelah pindah rumah. Objek Nilai tidak memiliki identitas; dua objek nilai dengan atribut yang sama dapat saling menggantikan, seperti dua lembar uang $5. Tanyakan: "jika setiap bidang berubah, apakah ini masih hal yang sama?" Jika ya, itu adalah entitas.

Objek Nilai

Objek nilai bersifat tidak dapat diubah dan memvalidasi dirinya sendiri. Properti readonly pada PHP 8.1 menegakkan sifat tidak dapat diubah; konstruktor menjaga invarian sehingga instans yang tidak valid tidak mungkin ada.

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

Kesetaraan berdasarkan nilai

Objek nilai dibandingkan berdasarkan kesetaraan struktural, bukan referensi. Sediakan metode equals() yang eksplisit, alih-alih mengandalkan ==, karena perbandingan longgar PHP memiliki aturan yang dapat mengejutkan. Objek nilai Money harus mempertimbangkan jumlah dan mata uang.

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

Ketidakberubahan dan metode pembentuk nilai baru

Karena objek nilai tidak dapat diubah, "mengubah" salah satunya berarti mengembalikan instans baru. Metode seperti add() atau withAmount() tidak pernah mengubah objek; metode tersebut menghasilkan nilai baru. Hal ini menghilangkan galat aliasing dan membuat objek nilai aman untuk dibagikan secara bebas di seluruh domain.

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

Entitas

Entitas ditentukan oleh identitas, biasanya pengidentifikasi yang dibuat oleh domain, bukan penomoran otomatis database. Kesetaraan membandingkan pengidentifikasi. Atributnya dapat berubah melalui metode yang kaya perilaku dan melindungi invarian.

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

Pembuatan identitas

Utamakan pembuatan identitas di dalam domain (misalnya UUID) sebelum persistensi, alih-alih menunggu database. Dengan demikian, Anda dapat membentuk entitas yang sepenuhnya valid di memori, merujuknya di berbagai agregat, dan melakukan pengujian tanpa database. Pengidentifikasi merupakan bagian dari model, bukan artefak penyimpanan.

Perilaku kaya, bukan data anemia

Antipola yang umum adalah model domain anemia: entitas hanya berupa kumpulan pengambil/penyetel publik, sementara seluruh logika berada di kelas "layanan". DDD mendorong penempatan perilaku ke dalam entitas. $order->cancel() merangkum aturan pembatalan, alih-alih membiarkan pemanggil mengubah bidang status secara langsung.

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

Objek nilai di seluruh domain

Gantilah obsesi terhadap tipe primitif dengan objek nilai. Alih-alih meneruskan string $email, int $cents, dan string $currency ke berbagai tempat, bungkus semuanya dalam Email dan Money. Manfaat:

  • Validasi dilakukan sekali, saat pembuatan.
  • Aturan domain (pencocokan mata uang) berada bersama datanya.
  • Tanda tangan tipe mendokumentasikan maksud dan mencegah kekeliruan.

Catatan pemetaan persistensi

Objek nilai sering dipetakan ke kolom tersemat, bukan ke tabelnya sendiri (Doctrine #[Embeddable]). Entitas dipetakan ke baris yang menggunakan identitasnya sebagai kunci. Jauhkan urusan persistensi dari objek domain itu sendiri: model tidak seharusnya mengetahui bahwa dirinya disimpan di MySQL. ORM atau pemeta yang ditulis manual menerjemahkan antara domain yang kaya dan database.

Objek nilai gabungan

Objek nilai dapat disusun dari objek nilai lain. Address menggabungkan beberapa tipe primitif menjadi satu konsep utuh dengan kesetaraan dan pemformatannya sendiri. Entitas kemudian menyimpan satu tipe kaya, bukan lima string terpisah, dan aturan alamat berada di satu tempat.

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

Pemeriksaan Singkat

Entitas atau Objek Nilai?

Ringkasan

Anda telah mempelajari dua blok pembangun inti DDD. Entitas ditentukan oleh identitas yang stabil, memiliki perilaku kaya, dan melindungi invariantnya melalui metode. Objek Nilai tidak dapat diubah, memvalidasi dirinya sendiri, dan dibandingkan berdasarkan kesetaraan atribut, sehingga menggantikan obsesi terhadap tipe primitif. Pemodelan yang tepat, dengan logika berada di dalam objek alih-alih dalam kumpulan data anemia, merupakan dasar bagi agregat, repositori, dan bagian lain dari lapisan domain.

Pertanyaan yang Sering Diajukan

Apakah pelajaran “Blok Bangunan DDD: Entitas dan Objek Nilai” gratis?

Ya — teks lengkap “Blok Bangunan DDD: Entitas dan Objek Nilai” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus PHP Academy, upgrade ke CoddyKit PRO. Kursus PHP Academy mencakup 4 pelajaran total.

Apa yang akan aku pelajari di “Blok Bangunan DDD: Entitas dan Objek Nilai”?

Modelkan domain dengan entitas kaya perilaku dan objek nilai yang tidak dapat diubah. Kamu berlatih PHP Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.

Apakah aku perlu pengalaman untuk memulai PHP Academy?

Tidak diperlukan pengalaman sebelumnya. PHP Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 1 dari 4.

Berapa lama pelajaran “Blok Bangunan DDD: Entitas dan Objek Nilai” memakan waktu?

Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.

Bisakah aku menulis dan menjalankan kode dalam pelajaran PHP Academy ini?

Ya. Setiap pelajaran PHP Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.

Semua pelajaran dalam kursus ini

  1. Blok Bangunan DDD: Entitas dan Objek Nilai
  2. Agregat, Repositori, dan Factory
  3. Peristiwa Domain dan Layanan Domain
  4. Konteks Terbatas dan Pemetaan Konteks
← Kembali ke PHP Academy