Jika tim Anda memakai CodeIgniter 4 dan ingin mempercepat feedback sebelum code review, dua alat yang paling praktis untuk dipasang lebih awal adalah PHP CS Fixer untuk konsistensi style code dan PHPStan untuk static analysis. Keduanya membantu menangkap masalah yang seharusnya tidak perlu ditemukan manual saat review: format code yang tidak konsisten, pemanggilan method yang salah, null handling yang lemah, sampai asumsi tipe data yang berisiko bug.

Pada artikel ini, kita akan menyiapkan CodeIgniter 4: setup PHP CS Fixer dan PHPStan untuk review lebih cepat dengan pendekatan yang aman untuk tim. Fokusnya bukan release flow, tetapi workflow developer lokal dan integrasi sederhana ke CI agar feedback muncul lebih cepat tanpa langsung memblokir legacy code.

Mengapa PHP CS Fixer dan PHPStan dipasang di proyek CodeIgniter 4

Kedua tool ini menyelesaikan masalah yang berbeda.

  • PHP CS Fixer memeriksa dan memperbaiki style code secara otomatis. Ini mengurangi komentar review seperti spasi, import tidak terpakai, urutan statement, atau format array.
  • PHPStan menganalisis code tanpa menjalankannya. Tool ini berguna untuk mendeteksi error yang sering lolos saat testing manual, misalnya akses property pada nilai yang bisa null, return type yang tidak konsisten, atau pemanggilan method yang tidak ada.

Di proyek CodeIgniter 4, manfaatnya terasa karena struktur aplikasi biasanya tersebar di app/, tests/, helper, controller, model, dan validasi. Static analysis membantu menjaga konsistensi antar-layer tersebut, sementara fixer menjaga diffs tetap bersih dan review fokus ke logika bisnis.

Catatan: PHP CS Fixer tidak menjamin code benar secara logika, dan PHPStan tidak menggantikan test. Keduanya adalah lapisan feedback cepat sebelum test dan review manusia.

Instalasi via Composer

Pasang kedua tool sebagai dependency development agar tidak ikut menjadi dependency produksi.

composer require --dev friendsofphp/php-cs-fixer phpstan/phpstan

Setelah instalasi, binary biasanya bisa dijalankan melalui vendor/bin. Di proyek CodeIgniter 4, simpan file konfigurasi di root project agar mudah dipakai lokal maupun di CI.

Struktur file konfigurasi yang disarankan

Struktur sederhana yang mudah dipelihara biasanya seperti ini:

project-root/
├── app/
├── public/
├── tests/
├── vendor/
├── composer.json
├── php-cs-fixer.php
└── phpstan.neon

Penempatan ini memudahkan eksekusi perintah dari root project dan konsisten untuk semua developer.

Konfigurasi PHP CS Fixer

Tujuan konfigurasi awal adalah aman untuk tim: rapikan style yang umum, jangan terlalu agresif, dan batasi scope ke folder yang memang kita kontrol seperti app/ dan tests/.

Contoh file php-cs-fixer.php

<?php

$finder = PhpCsFixer\Finder::create()
    ->in([
        __DIR__ . '/app',
        __DIR__ . '/tests',
    ])
    ->name('*.php')
    ->ignoreDotFiles(true)
    ->ignoreVCS(true);

return (new PhpCsFixer\Config())
    ->setRiskyAllowed(false)
    ->setRules([
        '@PSR12' => true,
        'array_syntax' => ['syntax' => 'short'],
        'no_unused_imports' => true,
        'single_quote' => true,
        'trailing_comma_in_multiline' => ['elements' => ['arrays']],
        'binary_operator_spaces' => [
            'default' => 'single_space',
        ],
    ])
    ->setFinder($finder);

Mengapa aturan ini cukup aman

  • @PSR12 memberi baseline style yang umum dipahami.
  • no_unused_imports membantu membersihkan import yang tidak terpakai, sesuatu yang sering menumpuk saat refactor.
  • array_syntax dan single_quote membuat style lebih konsisten tanpa mengubah perilaku aplikasi.
  • setRiskyAllowed(false) mencegah rule yang berpotensi mengubah perilaku code secara semantik.

Untuk tahap awal, hindari rule yang terlalu opinionated jika tim belum sepakat. Tujuannya adalah mengurangi friksi adopsi, bukan memenangkan perdebatan style.

Perintah lokal PHP CS Fixer

Gunakan mode check saat ingin memvalidasi tanpa mengubah file, dan mode fix saat ingin memperbaiki otomatis.

vendor/bin/php-cs-fixer fix --dry-run --diff
vendor/bin/php-cs-fixer fix

--dry-run --diff cocok dipakai sebelum commit karena menampilkan file mana yang perlu dirapikan. Saat perubahan memang hanya style, jalankan fix agar review tidak dipenuhi komentar format.

Konfigurasi PHPStan untuk CodeIgniter 4

Static analysis paling efektif jika dimulai dari level yang realistis. Jika proyek masih punya banyak legacy code, memulai dari level terlalu tinggi justru membuat output penuh noise dan akhirnya diabaikan.

Level analisis yang aman untuk tim

Untuk banyak tim, memulai dari level menengah lebih aman daripada langsung agresif. Secara praktik, pilih level yang sudah memberi sinyal berguna tetapi tidak langsung menghasilkan ratusan error lama. Setelah code baru lebih bersih, level bisa dinaikkan bertahap.

Yang penting bukan angka levelnya, tetapi kualitas feedback. Jika output masih terlalu banyak false positive atau error legacy, kecil kemungkinan developer akan rutin menjalankannya.

Contoh file phpstan.neon

parameters:
    level: 5
    paths:
        - app
        - tests
    tmpDir: writable/cache/phpstan
    treatPhpDocTypesAsCertain: false

    excludePaths:
        - */Views/*

    scanFiles: []

Konfigurasi di atas sengaja sederhana:

  • paths dibatasi ke app dan tests agar fokus ke code aplikasi.
  • excludePaths dapat dipakai untuk mengecualikan area yang kurang cocok dianalisis ketat, misalnya view jika banyak campuran template PHP.
  • tmpDir diarahkan ke folder writable agar cache analisis tidak mengotori root project.
  • treatPhpDocTypesAsCertain: false bisa membantu mengurangi rasa aman palsu jika dokumentasi tipe belum konsisten.

Jika proyek Anda punya folder helper khusus atau library internal di luar app/, tambahkan ke paths secara eksplisit.

Perintah lokal PHPStan

vendor/bin/phpstan analyse
vendor/bin/phpstan analyse app tests

Menjalankan dengan path eksplisit berguna saat Anda ingin fokus ke area tertentu setelah refactor.

Skrip Composer agar workflow lokal lebih ringkas

Agar developer tidak perlu mengingat command panjang, tambahkan script di composer.json.

{
  "scripts": {
    "cs:check": "php-cs-fixer fix --dry-run --diff",
    "cs:fix": "php-cs-fixer fix",
    "stan": "phpstan analyse",
    "qa": [
      "@cs:check",
      "@stan"
    ]
  }
}

Setelah itu, workflow lokal menjadi lebih pendek:

composer cs:check
composer cs:fix
composer stan
composer qa

Rekomendasi praktis: jalankan composer cs:fix sebelum commit, lalu composer stan sebelum membuka pull request. Dengan pola ini, reviewer menerima diff yang lebih bersih dan lebih sedikit error dasar.

Contoh temuan umum di proyek CodeIgniter 4

Bagian ini penting karena nilai utama tool bukan pada instalasinya, tetapi pada jenis masalah yang benar-benar bisa ditangkap lebih cepat.

1. Controller: akses input dan null handling

<?php

namespace App\Controllers;

use CodeIgniter\Controller;

class UserController extends Controller
{
    public function show(): string
    {
        $id = $this->request->getGet('id');

        if ($id === null || $id === '') {
            return 'ID tidak valid';
        }

        return 'User ID: ' . (string) $id;
    }
}

Temuan yang umum:

  • Nilai request diasumsikan selalu ada, padahal bisa null.
  • Penggabungan string dengan nilai yang tipenya belum jelas.
  • Return type dideklarasikan, tetapi ada cabang logika yang tidak konsisten.

PHPStan membantu mengingatkan bahwa input eksternal tidak boleh langsung diasumsikan bertipe tertentu.

2. Model: hasil query diasumsikan selalu ditemukan

<?php

$user = $userModel->find($id);

if ($user === null) {
    throw new \RuntimeException('User tidak ditemukan');
}

$email = $user['email'] ?? null;

Pola bug yang sering muncul di model atau service:

  • Hasil find() diasumsikan selalu array padahal bisa tidak ada.
  • Akses key array langsung tanpa pengecekan.
  • Method mengembalikan tipe campuran tetapi dipakai seolah selalu satu tipe.

Di sini PHPStan memaksa developer lebih eksplisit menangani kondisi data tidak ditemukan.

3. Validation: aturan dan data tidak sinkron

<?php

$data = [
    'email' => $this->request->getPost('email'),
];

$rules = [
    'email' => 'required|valid_email',
];

Masalah yang sering terjadi bukan hanya pada rules, tetapi pada pemakaian hasil validasi setelahnya. Misalnya developer menganggap field pasti ada dan bertipe string, padahal input bisa kosong atau tidak terkirim. Static analysis tidak memahami seluruh aturan validasi runtime, tetapi tetap berguna untuk mendeteksi asumsi tipe yang terlalu optimistis di code setelah validasi.

4. Helper: fungsi global, import, dan return type tidak jelas

<?php

if (! function_exists('format_price')) {
    function format_price(?float $amount): string
    {
        if ($amount === null) {
            return '-';
        }

        return number_format($amount, 0, ',', '.');
    }
}

Helper sering menjadi sumber masalah karena:

  • Fungsi global jarang diberi type hint.
  • Return type bercampur, kadang string kadang null.
  • Nama fungsi bentrok atau tidak konsisten.

Menambahkan parameter type dan return type sederhana seperti di atas membuat PHPStan jauh lebih berguna.

Kesalahan umum saat setup

Memasukkan terlalu banyak path sejak awal

Jika langsung menganalisis seluruh project termasuk folder yang generated, vendor override, atau template yang tidak konsisten, output akan cepat penuh noise. Mulailah dari app/ dan tests/.

Memakai level terlalu tinggi untuk codebase lama

Ini sering membuat pipeline merah terus-menerus tanpa arah perbaikan yang jelas. Lebih baik level moderat tetapi dipakai rutin daripada level tinggi yang diabaikan.

Mengandalkan PHPDoc yang belum rapi

Jika dokumentasi tipe di codebase belum konsisten, jangan terlalu cepat mempercayainya. Perbaiki type hint native di parameter dan return type terlebih dahulu karena itu paling mudah diverifikasi.

Menjalankan fixer di seluruh repo tanpa pembatasan

Batasi finder ke folder aplikasi yang memang ingin distandardisasi. Jika tidak, diff pertama akan terlalu besar dan sulit direview.

Integrasi sederhana ke CI

Untuk CI, tujuan awal cukup sederhana: jalankan check style dan static analysis pada branch atau pull request. Tidak perlu membahas release flow atau deployment; cukup pastikan CI menjalankan command yang sama dengan lokal agar hasilnya konsisten.

composer cs:check
composer stan

Pendekatan ini penting karena:

  • Developer bisa mereproduksi hasil CI dari laptop dengan command yang sama.
  • Review tidak tertunda karena masalah style atau static error dasar.
  • Tim punya baseline kualitas yang jelas tanpa proses yang rumit.

Jika pipeline mulai lambat, optimalkan dulu scope path dan caching tool sebelum menambah aturan baru.

Strategi adopsi bertahap agar legacy code tidak langsung memblokir pipeline

Masalah terbesar biasanya bukan di tool, tetapi di code lama yang sudah terlanjur tidak konsisten. Agar adopsi berhasil, gunakan strategi bertahap berikut:

  1. Mulai dari folder aktif, misalnya app/Controllers, app/Models, dan tests/.
  2. Pakai level PHPStan yang moderat lebih dulu, lalu naikkan setelah error baru stabil rendah.
  3. Jalankan PHP CS Fixer sebagai auto-fix lokal, tetapi gunakan mode check di CI.
  4. Fokus pada code yang disentuh. Jika file legacy diubah, rapikan sekalian bagian yang relevan, tidak harus seluruh codebase sekaligus.
  5. Jangan langsung blokir semua error lama. Pisahkan antara baseline masalah lama dan aturan untuk code baru jika memang diperlukan.

Dengan cara ini, pipeline tetap berguna tanpa membuat tim tersendat karena utang teknis lama. Seiring waktu, kualitas code akan naik secara alami di area yang paling sering disentuh.

Penutup

CodeIgniter 4: setup PHP CS Fixer dan PHPStan untuk review lebih cepat adalah langkah praktis untuk memindahkan feedback dasar dari tahap code review ke tahap lokal developer dan CI sederhana. PHP CS Fixer membantu menjaga style tetap konsisten, sedangkan PHPStan menangkap asumsi tipe dan potensi bug sebelum aplikasi dijalankan.

Mulailah dengan konfigurasi yang sempit, level analisis yang realistis, dan command yang mudah dijalankan lewat Composer. Setelah tim terbiasa, Anda bisa memperluas cakupan dan menaikkan standar secara bertahap tanpa membuat legacy code langsung memblokir pipeline.