Tips Struktur Kode PHP yang Bersih
PHP Best Practices #php #clean-code #best-practices #oop

Tips Struktur Kode PHP yang Bersih

A
Abd. Asis
5 min read
Bagikan:

Kode yang bekerja dan kode yang mudah dirawat adalah dua hal yang berbeda. PHP punya reputasi lama sebagai bahasa yang gampang berakhir menjadi tumpukan logika kusut — bukan karena bahasanya buruk, tapi karena ia sangat permisif. Tidak ada yang mencegah kita menulis seluruh aplikasi dalam satu file, mencampur query database dengan HTML, atau menamai variabel $x, $temp, dan $data2.

Masalah mulai terasa saat aplikasi tumbuh atau saat developer lain — atau diri sendiri enam bulan ke depan — harus menyentuh kode tersebut. Bagian ini membahas lima prinsip yang bisa langsung diterapkan untuk membuat kode PHP lebih mudah dibaca, di-debug, dan dikembangkan.

Penamaan yang Berbicara Sendiri

Nama variabel, fungsi, dan kelas adalah dokumentasi yang paling sering dibaca. Nama yang baik menghilangkan kebutuhan komentar penjelas untuk hal-hal yang seharusnya sudah jelas dari kodenya.

Bandingkan dua versi berikut:

// Sulit dibaca: apa itu $d, $s, dan $r?
function calc($d, $s) {
    $r = $d * (1 - $s / 100);
    return $r;
}
// Jelas tanpa perlu komentar
function applyDiscount(float $originalPrice, float $discountPercent): float {
    return $originalPrice * (1 - $discountPercent / 100);
}

Versi kedua tidak hanya lebih mudah dibaca — ia juga lebih mudah di-test karena nama parameternya mencerminkan intent bisnis. Gunakan kata benda untuk variabel dan kelas, kata kerja untuk fungsi.

Jika butuh komentar untuk menjelaskan apa yang dilakukan sebuah variabel atau fungsi, itu tanda bahwa namanya perlu diperbaiki — bukan ditambah komentar.

Satu Fungsi, Satu Tanggung Jawab

Fungsi yang melakukan terlalu banyak hal sekaligus adalah sumber utama bug yang sulit dilacak. Saat ada masalah, sulit menentukan bagian mana yang salah karena satu fungsi merangkap terlalu banyak peran.

Perhatikan pola berikut yang sering ditemukan di codebase lawas:

// Fungsi ini melakukan tiga hal sekaligus: validasi, simpan, kirim email
function processRegistration(array $data): bool {
    if (empty($data['email']) || !filter_var($data['email'], FILTER_VALIDATE_EMAIL)) {
        return false;
    }

    $userId = DB::table('users')->insertGetId([
        'name'  => $data['name'],
        'email' => $data['email'],
    ]);

    mail($data['email'], 'Selamat datang!', 'Akun kamu sudah aktif.');

    return $userId > 0;
}

Versi yang lebih mudah dirawat memisahkan ketiga tanggung jawab tersebut:

function validateRegistrationData(array $data): bool {
    return !empty($data['email']) && filter_var($data['email'], FILTER_VALIDATE_EMAIL);
}

function saveNewUser(array $data): int {
    return DB::table('users')->insertGetId([
        'name'  => $data['name'],
        'email' => $data['email'],
    ]);
}

function sendWelcomeEmail(string $email): void {
    mail($email, 'Selamat datang!', 'Akun kamu sudah aktif.');
}

Sekarang setiap fungsi bisa di-test secara independen. Jika pengiriman email gagal, debugnya tidak perlu menyentuh logika validasi atau penyimpanan data.

Struktur Direktori yang Logis

Cara kita menyusun file mencerminkan cara kita memahami domain aplikasi. Tidak ada satu standar yang berlaku universal, tapi prinsip umumnya adalah: letakkan hal-hal yang berubah bersama di tempat yang sama.

Struktur MVC klasik sudah cukup untuk aplikasi berukuran sedang:

src/
├── Controllers/
│   ├── ProjectController.php
│   └── TaskController.php
├── Models/
│   ├── Project.php
│   └── Task.php
├── Services/
│   ├── ProjectService.php
│   └── NotificationService.php
└── Repositories/
    ├── ProjectRepository.php
    └── TaskRepository.php

Layer Services menampung logika bisnis yang tidak cocok di controller maupun model. Layer Repositories mengisolasi akses data sehingga bisa diganti implementasinya tanpa menyentuh logika bisnis. Pemisahan ini membuat setiap lapisan punya satu alasan untuk berubah.

Untuk aplikasi yang lebih besar, pendekatan berbasis fitur (feature-based) sering lebih efektif daripada pengelompokan berdasarkan jenis file — tapi itu topik tersendiri.

Hindari Duplikasi dengan Prinsip DRY

DRY (Don’t Repeat Yourself) bukan tentang obsesi menghapus semua kode yang terlihat mirip. Ini tentang memastikan setiap pengetahuan bisnis punya satu representasi tunggal di codebase.

Contoh nyata: format tanggal untuk tampilan di UI. Jika logika formatnya ditulis ulang di setiap controller atau view, mengubah formatnya berarti harus mencari semua tempatnya satu per satu:

// Tersebar di berbagai tempat — rawan tidak konsisten
echo date('d M Y', strtotime($project->created_at));
echo date('d M Y', strtotime($task->due_date));
echo date('d M Y', strtotime($report->generated_at));

Sentralisasikan ke satu tempat:

// src/Helpers/DateHelper.php
function formatDisplayDate(string $dateString): string {
    return date('d M Y', strtotime($dateString));
}

// Di mana pun butuh format ini
echo formatDisplayDate($project->created_at);

Sekarang saat format perlu diubah — misalnya ke d/m/Y — cukup ubah di satu tempat. Prinsip ini terhubung erat dengan penggunaan Strategy Pattern ketika variasi perilaku perlu dikelola dengan lebih terstruktur.

Komentar untuk Alasan, Bukan untuk Penjelasan “Apa”

Komentar yang menjelaskan apa yang dilakukan kode adalah komentar yang paling cepat basi. Saat kode diubah, komentar sering tertinggal dan menjadi menyesatkan. Komentar yang bertahan lama adalah yang menjelaskan mengapa keputusan tertentu diambil.

// Buruk: komentar menjelaskan "apa" yang sudah jelas dari kodenya
// Ambil semua proyek yang statusnya aktif
$activeProjects = Project::where('status', 'active')->get();

// Baik: komentar menjelaskan "mengapa" ada batasan ini
// Maksimal 50 proyek per halaman berdasarkan benchmark performa
// di server dengan RAM 2GB — lihat issue #247
$activeProjects = Project::where('status', 'active')->limit(50)->get();

Komentar kedua memberi konteks yang tidak bisa ditemukan dari kodenya sendiri. Siapapun yang membaca tahu alasan di balik angka 50, dan tahu ke mana harus merujuk jika perlu mengubahnya.

Untuk pola OOP yang lebih dalam, prinsip Tell, Don’t Ask adalah kelanjutan natural dari pembahasan ini — cara membuat objek PHP yang tidak “bocor” implementasinya ke luar.

Kesimpulan

Struktur kode bukan tentang mengikuti aturan demi aturan itu sendiri, tapi tentang memperlambat laju kode yang menjadi tidak terkendali seiring waktu. Lima prinsip di atas — penamaan yang bermakna, fungsi yang terfokus, direktori yang logis, menghindari duplikasi, dan komentar yang tepat sasaran — adalah fondasi yang bisa diterapkan di proyek PHP apapun, dari script sederhana hingga aplikasi enterprise.

Referensi

  1. 1PHP Manual — php.net
  2. 2PSR-12: Extended Coding Style — PHP-FIG
  3. 3PHP: The Right Way — phptherightway.com

Tentang Penulis

Abd. Asis

Abd. Asis

Software Developer dan Laravel Programmer dari Madura, Indonesia. Passionate tentang PHP, Laravel, dan teknologi web modern.

Komentar