Pendahuluan — pintu terakhir sebelum Laravel

Di Property, Method & Constructor (#54) kamu sudah bisa membuat object Buku yang lahir lengkap. Artikel ini adalah #55 (ini) — langkah ketiga (dan terakhir) jembatan OOP PHP sebelum Laravel.

Dua ide saja yang kita rapikan: visibility (siapa boleh menyentuh data) dan composition (object memakai object lain). Analoginya: laci buku boleh dikunci (private), dan perpustakaan memakai banyak buku — bukan “jadi buku”.

Prasyarat: sudah baca Property, Method & Constructor (#54) — paham class, property, method, dan __construct. Domain tetap perpustakaan mini.

Visibility — siapa boleh menyentuh?

Kata kunci Arti awam Kapan dipakai di artikel ini
public Boleh disentuh dari luar class Method yang memang untuk dipanggil pemakai
private Hanya class sendiri yang boleh Property penting agar tidak diacak sembarangan
protected Untuk class anak (inheritance) Disebut saja — belum kita dalami di sini

Jangan hafal semua dulu. Fokus: public vs private. Itu sudah cukup untuk jembatan ke Laravel.

Masalah kalau semua public

Property public nyaman, tapi mudah “dirusak” dari luar:

<?php
class Buku
{
    public string $judul;
    public int $tahun;

    public function __construct(string $judul, int $tahun)
    {
        $this->judul = $judul;
        $this->tahun = $tahun;
    }
}

$buku = new Buku("Belajar PHP", 2024);
$buku->tahun = -99; // oops — tahun mustahil, tapi PHP diam saja
echo $buku->tahun, PHP_EOL;

Output:

-99

Object tetap “hidup”, tapi datanya sudah tidak masuk akal. Di aplikasi web, bug seperti ini sering datang dari form/API yang mengisi field sembarangan.

Private + method — laci terkunci

Kunci property dengan private, lalu sediakan method yang mengontrol perubahan:

<?php
class Buku
{
    private string $judul;
    private int $tahun;

    public function __construct(string $judul, int $tahun)
    {
        $this->judul = $judul;
        $this->setTahun($tahun);
    }

    public function info(): string
    {
        return "{$this->judul} ({$this->tahun})";
    }

    public function setTahun(int $tahun): void
    {
        if ($tahun < 1900 || $tahun > 2100) {
            throw new InvalidArgumentException("Tahun tidak masuk akal: {$tahun}");
        }
        $this->tahun = $tahun;
    }
}

$buku = new Buku("Belajar PHP", 2024);
echo $buku->info(), PHP_EOL;

Output:

Belajar PHP (2024)

Dari luar class, $buku->tahun = -99 akan ditolak PHP (Cannot access private property). Perubahan tahun harus lewat setTahun() — satu pintu, satu aturan.

Kalau kamu kirim tahun mustahil lewat pintu itu — misalnya $buku->setTahun(1800) — PHP akan melempar InvalidArgumentException (pesan error yang kita tulis sendiri). Itu sengaja: lebih baik gagal keras daripada menyimpan data bohong.

Awam: private bukan “rahasia negara”. Ia artinya: “kalau mau ubah, lewat pintu yang sudah kita sediakan.”

public = pintu · private = laci dalam class Buku private $judul, $tahun public info() / setTahun() aturan hidup di method kode di luar class boleh: $buku->info() tidak: $buku->tahun = -99
Pemakai object hanya lewat method public. Data penting tetap di laci private.

Composition — object memakai object

Composition artinya: sebuah object memiliki / memakai object lain. Bukan “mewarisi” (inheritance) — itu topik lain dan sering keburu rumit untuk awam.

Contoh: Katalog menyimpan banyak Buku. Katalog bukan buku; ia mengumpulkan buku.

<?php
class Buku
{
    private string $judul;

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

    public function judul(): string
    {
        return $this->judul;
    }
}

class Katalog
{
    /** @var list<Buku> daftar Buku di dalam katalog */
    private array $koleksi = [];

    public function tambah(Buku $buku): void
    {
        $this->koleksi[] = $buku;
    }

    public function jumlah(): int
    {
        return count($this->koleksi);
    }

    public function daftar(): string
    {
        $baris = [];
        foreach ($this->koleksi as $buku) {
            $baris[] = "- ".$buku->judul();
        }
        return implode(PHP_EOL, $baris);
    }
}

$katalog = new Katalog();
$katalog->tambah(new Buku("Belajar PHP"));
$katalog->tambah(new Buku("Laravel Praktis"));
echo "jumlah=", $katalog->jumlah(), PHP_EOL;
echo $katalog->daftar(), PHP_EOL;

Output:

jumlah=2
- Belajar PHP
- Laravel Praktis

Ini pola yang nanti sering muncul di Laravel: controller tipis (pintu HTTP — terima request, kirim jawaban) dan service / class domain (tempat aturan bisnis). Ide-nya sama: potong tanggung jawab, jangan satukan semua di satu file panjang.

Awam: baris @var list<Buku> di komentar hanya catatan untuk manusia/IDE — “koleksi ini isinya object Buku”. PHP tidak wajib membacanya agar program jalan.

Pola Dasar — visibility & composition

  1. 1
    Kunci data penting Property kritis = private (tahun, stok, harga, status).
  2. 2
    Buka pintu lewat method info(), setTahun(), judul() — aturan hidup di sini.
  3. 3
    Pisahkan “benda” dan “pengelola” Buku vs Katalog — jangan saturasi satu class raksasa.
  4. 4
    Composition dulu, inheritance belakangan “Memakai” object lain biasanya lebih mudah dipahami awam.
  5. 5
    Baru bawa ke Laravel Berikutnya: Laravel routing & JSON (#56) — pintu HTTP nyata di framework.

Kode lengkap — oop_php_visibility.php

Simpan dan jalankan: php oop_php_visibility.php. Perhatikan: property private, perubahan lewat method, dan Katalog yang memakai Buku.

<?php
/**
 * Visibility & composition ringan (Seri 4 #55).
 * Lanjut: Laravel routing & JSON di artikel berikutnya.
 */

declare(strict_types=1);

class Buku
{
    private string $judul;
    private string $penulis;
    private int $tahun;

    public function __construct(string $judul, string $penulis, int $tahun)
    {
        $this->judul = $judul;
        $this->penulis = $penulis;
        $this->setTahun($tahun);
    }

    public function info(): string
    {
        return "{$this->judul} oleh {$this->penulis} ({$this->tahun})";
    }

    public function setTahun(int $tahun): void
    {
        if ($tahun < 1900 || $tahun > 2100) {
            throw new InvalidArgumentException("Tahun tidak masuk akal: {$tahun}");
        }
        $this->tahun = $tahun;
    }
}

class Katalog
{
    /** @var list<Buku> daftar Buku di dalam katalog */
    private array $koleksi = [];

    public function tambah(Buku $buku): void
    {
        $this->koleksi[] = $buku;
    }

    public function jumlah(): int
    {
        return count($this->koleksi);
    }

    public function daftar(): string
    {
        $baris = [];
        foreach ($this->koleksi as $buku) {
            $baris[] = $buku->info();
        }
        return implode(PHP_EOL, $baris);
    }
}

function demo(): void
{
    $katalog = new Katalog();
    $katalog->tambah(new Buku("Belajar PHP", "Sari", 2024));
    $katalog->tambah(new Buku("Laravel Praktis", "Budi", 2025));

    echo $katalog->daftar(), PHP_EOL;
    echo "jumlah=", $katalog->jumlah(), PHP_EOL;
}

demo();

Output yang diharapkan:

Belajar PHP oleh Sari (2024)
Laravel Praktis oleh Budi (2025)
jumlah=2

Kesalahan umum

Gejala Penyebab tipikal Perbaikan
Cannot access private property Mengisi property private dari luar Pakai method public (getter/setter/aturan)
Data tetap “liar” Property masih public Kunci dengan private + validasi di method
Class raksasa Semua logika digabung ke Buku Pisah pengelola: Katalog / service tipis
Langsung warisan rumit Loncat ke inheritance Composition dulu — “memakai”, bukan “menjadi”
Langsung buka Laravel Fondasi object belum rapat Selesaikan jembatan OOP PHP dulu (Mengenal OOP PHP (#53) sampai #55 (ini))

Latihan singkat

  1. Tambah method judul(): string di Buku (kode lengkap) yang mengembalikan judul private.
  2. Di setTahun(), coba kirim tahun 1800 dan pastikan exception muncul (hapus dulu dari demo jika perlu).
  3. Tambah buku ketiga ke Katalog dan pastikan jumlah= menjadi 3.

FAQ singkat

Harus selalu private?
Untuk data yang punya aturan (tahun, stok, status): ya, lebih aman. Method yang memang untuk dipanggil pemakai: biarkan public.

Apa bedanya composition dan inheritance?
Composition = “memakai” (katalog punya buku). Inheritance = “menjadi jenis khusus dari”. Di Seri 4 kita prioritaskan composition karena lebih mudah dibawa ke service Laravel.

Apakah ini sudah cukup untuk Laravel?
Untuk fondasi object: ya. Berikutnya kita pakai framework untuk route HTTP & JSON — ide object-nya tetap sama.

Lanjut ke mana?
Berikutnya: Laravel Routing & JSON (#56) — pintu HTTP nyata, artikel pertama stack Laravel di Seri 4.

Kesimpulan & langkah berikutnya

private melindungi data. Method public menjadi pintu. Composition membagi kerja antar object. Tiga kebiasaan ini yang membuat controller Laravel tidak jadi tempat sampah.

Artikel ini adalah #55 (ini) — penutup jembatan OOP PHP setelah Property, Method & Constructor (#54) dan Mengenal OOP PHP (#53).

Seri 4 progress: langkah #55 (ini) · 6/8 menuju Capstone Laravel · jembatan OOP PHP 3/3 selesai · prasyarat: Property, Method & Constructor (#54) LIVE. Berikutnya: Laravel Routing & JSON (#56).