Hampir setiap tim PHP pernah memiliki dokumen “pedoman gaya kode” yang damai di suatu wiki — dibaca sekali saat onboarding, lalu dilupakan. Hasilnya mudah ditebak: setiap anggota menulis kode dengan gaya masing-masing, dan review pull request dipenuhi komentar soal spasi, urutan use, dan penempatan kurung kurawal yang seharusnya tidak perlu dikomentari manusia. Isi aturannya sendiri sudah kita bahas pada Chapter PHP Coding Standards
. Chapter ini membahas bagaimana aturan itu ditagih: ditegakkan oleh mesin, di tahap paling awal pipeline, sebelum static analysis dan test menyala.
Mesin yang Menegakkan Aturan #
Perhatian reviewer adalah sumber daya paling langka dalam sebuah tim, dan memboroskannya untuk memperdebatkan gaya kode adalah pemborosan yang paling mudah dihindari. Dua keluarga tool menuntaskan pekerjaan ini di ekosistem PHP:
- PHP-CS-Fixer — membaca kode, membandingkannya dengan himpunan aturan, lalu memperbaiki pelanggaran secara otomatis; dengan mode dry-run, tool ini juga berfungsi sebagai pemeriksa.
- PHP_CodeSniffer (perintah
phpcs) — mendeteksi dan melaporkan pelanggaran terhadap standar seperti PSR-12 beserta nama aturan yang dilanggar; pendampingnyaphpcbfmemperbaiki sebagian pelanggaran yang terdeteksi.
Keduanya dipasang sebagai dependensi dev lewat Composer, sehingga seluruh tim dan CI memakai versi tool yang sama:
composer require --dev friendsofphp/php-cs-fixer
composer require --dev squizlabs/php_codesnifferPilihan di antara keduanya bukan keputusan agama: PHP-CS-Fixer unggul di perbaikan otomatis, PHP_CodeSniffer unggul di laporan yang menyebut aturan mana yang dilanggar. Banyak proyek memakai salah satunya secara konsisten — yang terpenting adalah memilih satu lalu menegakkannya di semua tempat.
Konfigurasi PHP-CS-Fixer #
PHP-CS-Fixer dikendalikan oleh berkas konfigurasi berbahasa PHP, bukan YAML — artinya konfigurasi Anda boleh memakai logika biasa. Nama bakunya .php-cs-fixer.dist.php dan diletakkan di akar proyek:
<?php
$finder = (new PhpCsFixer\Finder())
->in([__DIR__ . '/src', __DIR__ . '/tests']);
return (new PhpCsFixer\Config())
->setRules([
'@PSR12' => true,
'array_syntax' => ['syntax' => 'short'],
'concat_space' => ['spacing' => 'one'],
])
->setFinder($finder);Mari kita baca isinya:
$findermembatasi cakupan pemeriksaan ke direktorisrcdantests; berkas divendor/tidak ikut diperiksa karena bukan milik kita.'@PSR12' => truemengaktifkan seluruh aturan standar PSR-12 sebagai fondasi.- Dua aturan tambahan menunjukkan bahwa konvensi internal tim tetap bisa lebih ketat daripada standar publik: sintaks array pendek
[...]dan spasi di sekitar operator penggabung string. returnmenyerahkan objek konfigurasi kepada tool yang menjalankannya.
Perintahnya hadir dalam dua ragam — memperbaiki langsung, atau sekadar memeriksa:
vendor/bin/php-cs-fixer fix
vendor/bin/php-cs-fixer fix --dry-run --diffTanpa argumen tambahan, fix menulis perubahan langsung ke berkas. Dengan --dry-run --diff, tidak ada berkas yang disentuh; tool hanya menampilkan diff yang akan diterapkan dan keluar dengan exit code bukan nol bila ada berkas yang perlu diubah — perilaku inilah yang membuatnya cocok sebagai tahap CI.
Pemeriksa Konvensi Mini #
Apa yang sebenarnya dikerjakan tool-tool di atas? Untuk menjawabnya, mari kita bangun pemeriksa konvensi mini untuk satu aturan sederhana: nama variabel harus camelCase. Pemeriksa menerima potongan kode sebagai string, lalu melaporkan nama-nama variabel yang melanggar aturan tersebut:
<?php
function cekPenamaanVariabel(string $kode): array
{
$pelanggaran = [];
if (preg_match_all('/\$([a-zA-Z_][a-zA-Z0-9_]*)/', $kode, $cocok)) {
foreach (array_unique($cocok[1]) as $nama) {
if (preg_match('/^[a-z][a-zA-Z0-9]*$/', $nama) === 0) {
$pelanggaran[] = $nama;
}
}
}
sort($pelanggaran);
return $pelanggaran;
}
$contohKode = <<<'KODE'
$totalBelanja = 150000;
$TOTAL_DISKON = 15000;
$stok_gudang = 42;
$member = true;
KODE;
foreach (cekPenamaanVariabel($contohKode) as $nama) {
echo "Pelanggaran penamaan: \$$nama\n";
}
$contohBersih = '$hargaSatuan = 50000;';
if (cekPenamaanVariabel($contohBersih) === []) {
echo "Contoh bersih: tidak ada pelanggaran\n";
}Output yang Dihasilkan:
Pelanggaran penamaan: $TOTAL_DISKON
Pelanggaran penamaan: $stok_gudang
Contoh bersih: tidak ada pelanggaranMari kita bedah logikanya baris per baris:
preg_match_allpertama menyisir seluruh kode dan menangkap setiap identifier yang diawali$, lengkap dengan huruf, angka, dan garis bawah di dalamnya.array_uniquemembuang nama yang muncul berulang agar satu variabel hanya dilaporkan sekali.preg_matchkedua menguji aturan camelCase: diawali huruf kecil ([a-z]), dilanjutkan huruf atau angka tanpa garis bawah ([a-zA-Z0-9]*). Nama yang tidak lolos pola dicatat sebagai pelanggaran.sortmengurutkan hasil agar laporan selalu sama urutannya antar eksekusi — deterministik dan mudah dibandingkan.- Pengulangan penutup mencetak setiap pelanggaran, lalu membuktikan jalur hijau dengan contoh yang bersih.
Dua nama terciduk: $TOTAL_DISKON (huruf besar dan garis bawah — gaya konstanta) dan $stok_gudang (snake_case). Sementara itu $totalBelanja dan $member lolos diam-diam karena sudah mematuhi aturan. Pemeriksa mini ini jujur tentang keterbatasannya: regex tidak paham konteks, sehingga $nama yang muncul di dalam string berkutip ganda pun akan ikut tersapu. Tool sungguhan seperti PHP-CS-Fixer karena itu memakai tokenizer PHP — ia melihat struktur bahasa, bukan sekadar teks — dan memeriksa ratusan aturan sekaligus. Namun pola dasarnya persis sama dengan fungsi kita di atas: aturan, pemindaian, laporan.
Urutan Stage: Lint Paling Awal #
Dalam pipeline, tahap pemeriksaan gaya — biasa disebut lint — ditempatkan sebelum static analysis dan test. Alasannya murni ekonomi: lint termurah, tidak mengeksekusi kode, selesai dalam hitungan detik, dan kegagalannya paling mekanis untuk diperbaiki. Gagal sedini mungkin berarti menit-menit tahap berikutnya tidak terbuang untuk sebuah spasi.
| Urutan | Tahap | Perintah contoh | Pipeline merah bila |
|---|---|---|---|
| 1 | lint | vendor/bin/php-cs-fixer fix --dry-run --diff | ada berkas yang akan diubah |
| 2 | static analysis | vendor/bin/phpstan analyse --no-progress | ada error analisis |
| 3 | test | vendor/bin/phpunit | ada test yang gagal |
Tahap 2 dibahas tuntas pada Chapter static analysis , dan seluruh Section ini membangun fondasi test-nya. Yang baru di sini adalah menyadari bahwa urutan ketiganya merupakan keputusan desain, bukan kebiasaan yang kebetulan terbentuk.
Warning Juga Gagal #
Kebijakan yang membedakan pipeline serius dari pipeline pajangan adalah warnings-as-errors: tidak ada kategori “kuning” yang boleh lolos. PHPUnit menyediakan flag khusus untuk menaikkan derajat warning:
vendor/bin/phpunit --fail-on-warningDengan flag tersebut, test yang menimbulkan Warning dihitung gagal meskipun seluruh assertion-nya lolos. Pada dua tahap lainnya kebijakan ini sudah menyatu secara bawaan: PHPStan keluar dengan exit code bukan nol untuk setiap error yang dilaporkan, dan php-cs-fixer --dry-run gagal untuk satu diff sekecil apa pun.
Menaikkan Standar Tanpa Drama #
Menegakkan standar pada proyek lama dengan ribuan berkas membutuhkan strategi agar tidak melumpuhkan tim, dan urutan berikut terbukti lancar. Pertama, jalankan vendor/bin/php-cs-fixer fix satu kali pada seluruh kode dalam pull request khusus; diff-nya besar tetapi murni mekanis, review cukup memastikan tidak ada perubahan perilaku, lalu merge. Kedua, segera setelah merge itu selesai, nyalakan tahap lint di CI — pelanggaran tidak punya jalan kembali. Ketiga, pasang format-on-save di editor: ekstensi PHP-CS-Fixer untuk VS Code dan integrasi PHP-CS-Fixer di PhpStorm menjalankan fixer setiap kali berkas disimpan, sehingga pelanggaran mati sebelum sempat terlihat oleh siapa pun.
Mulai titik itu, review kembali ke pekerjaan yang layak dikerjakan manusia: nama yang tepat, struktur yang masuk akal, dan logika yang benar. Gaya kode sudah menjadi urusan mesin — dan mesin tidak pernah lelah memperdebatkan spasi.
Ringkasan #
Coding standards bertahan bukan karena ditulis rapi di suatu wiki, melainkan karena ditagih otomatis: PHP-CS-Fixer atau PHP_CodeSniffer memeriksa setiap perubahan, tahap lint berjalan paling awal karena paling murah, warning diperlakukan sebagai kegagalan, dan editor memformat kode sebelum disimpan. Pemeriksa konvensi mini yang kita tulis menunjukkan pola dasarnya: aturan, pemindaian, laporan deterministik. Ketiga tahap pipeline — lint, static analysis, test — kini siap dirangkai. Chapter berikutnya menyatukannya menjadi continuous integration: satu pipeline otomatis yang berjalan pada setiap push.
Referensi #
- Standar PSR-12: https://www.php-fig.org/psr/psr-12/
- Panduan praktik PHP the right way: https://www.phptherightway.com/