# Modul Pembelajaran: PHP Encapsulation

## Bagian 1: Konsep Dasar

### 1.1. Apa itu Encapsulation?
Encapsulation (Enkapsulasi/Pengkapsulan) adalah konsep membungkus data (property) dan metode (method) menjadi satu kesatuan dalam sebuah class, serta membatasi akses ke komponen internal class tersebut.

**Tujuan Utama:**
1.  **Proteksi Data**: Mencegah data diubah sembarangan menjadi nilai yang tidak valid.
2.  **Information Hiding**: Menyembunyikan kompleksitas internal. Pengguna class tidak perlu tahu bagaimana data disimpan, cukup tahu cara menggunakannya.

---

## Bagian 2: Visibility Modifiers

PHP memiliki 3 level akses untuk property dan method:

1.  **Public** (`public`):
    -   Bisa diakses dari mana saja (Luar class, Dalam class, Child class).
    -   Ini adalah default jika tidak ditulis.
    
2.  **Protected** (`protected`):
    -   Bisa diakses oleh Class itu sendiri dan Class Turunannya (Child).
    -   **TIDAK** bisa diakses dari luar class.

3.  **Private** (`private`):
    -   Hanya bisa diakses oleh Class itu sendiri.
    -   Child class pun **TIDAK** bisa mengaksesnya.
    -   Ini adalah level paling ketat.

**Contoh:**
```php
class User {
    public $name;       // Siapa saja boleh lihat/ubah
    protected $email;   // Hanya User dan turunannya
    private $password;  // Hanya User sendiri
}
```

---

## Bagian 3: Setter & Getter

Karena property `private` tidak bisa diakses langsung, kita perlu menyediakan "Pintu Resmi" untuk membaca dan mengubahnya. Pintu ini disebut **Setter** dan **Getter**.

### 3.1. Setter (Mutator)
Method untuk mengubah nilai property. Di sini kita bisa menambahkan **Validasi**.

```php
public function setAge($age) {
    if ($age < 0) {
        throw new Exception("Umur tidak boleh minus!");
    }
    $this->age = $age;
}
```

### 3.2. Getter (Accessor)
Method untuk mengambil nilai property. Di sini kita bisa memformat output.

```php
public function getAge() {
    return $this->age . " tahun";
}
```

---

## Bagian 4: Read-only Properties (PHP 8.1+)

Kadang kita ingin sebuah property hanya bisa diisi sekali (immutable) dan tidak boleh diubah lagi. Daripada membuat property `private` + `getter` saja (tanpa setter), PHP 8.1 menyediakan keyword `readonly`.

**Aturan `readonly`:**
1.  Harus bertipe data (Typed Property).
2.  Hanya boleh diisi sekali (biasanya di Constructor).
3.  Tidak bisa diubah nilainya setelah diisi.

```php
class User {
    public readonly string $username;

    public function __construct($username) {
        $this->username = $username;
    }
}

$u = new User("admin");
echo $u->username; // OK
// $u->username = "hacker"; // ERROR!
```

---

## Bagian 5: Best Practices

1.  **Default to Private**: Saat membuat property, mulailah dengan `private`. Ubah ke `protected` atau `public` hanya jika benar-benar perlu.
2.  **Validasi di Setter**: Jangan biarkan data sampah masuk ke objek Anda. Lindungi integritas data dengan validasi di setter.
3.  **Gunakan Readonly**: Untuk data yang sifatnya konstan setelah pembuatan objek (seperti ID, Username, Tanggal Lahir), gunakan `readonly`.
4.  **Tell, Don't Ask**: Daripada mengambil data, memprosesnya di luar, lalu menyimpannya lagi (`get` -> proses -> `set`), lebih baik suruh objek memprosesnya sendiri lewat sebuah method.

**Contoh Tell Don't Ask:**
-   **Salah**: `$wallet->saldo = $wallet->saldo - 1000;`
-   **Benar**: `$wallet->withdraw(1000);`
