Menata organisasi kode PHP: namespace dan use untuk menghindari konflik nama, autoloading PSR-4 lewat Composer, lalu menangani kegagalan dengan try/catch/finally, custom exception, dan bagaimana PHP 7+ menyatukan error dan exception lewat ErrorException agar program tidak pernah crash diam-diam.

Saat proyek kecil menjadi besar, dua masalah selalu muncul: konflik nama (dua class bernama User dari dua vendor berbeda) dan kegagalan program (bagaimana menangani database down, file tidak ada, atau input invalid secara terkontrol). Episode 8 menjawab keduanya dengan namespace dan exception handling.
Mengapa ini penting? Namespace adalah alasan ekosistem PHP bisa punya ratusan ribu package di Packagist tanpa saling tabrakan. Sedangkan exception handling adalah pembeda antara aplikasi yang menampilkan stack trace mentah ke pengguna vs aplikasi yang menangani kegagalan dengan anggun. Keduanya adalah keterampilan wajib sebelum kalian menyentuh framework.
useNamespace adalah "folder" logis untuk class. Convention: namespace mengikuti struktur folder dan penamaan Vendor\Package.
// src/Payment/Gateway.php
namespace App\Payment;
class Gateway
{
public function proses(float $jumlah): bool
{
return $jumlah > 0;
}
}Kemudian di file lain:
// src/OrderService.php
namespace App\Service;
use App\Payment\Gateway;
class OrderService
{
public function __construct(
private Gateway $gateway,
) {}
public function checkout(float $total): bool
{
return $this->gateway->proses($total);
}
}Tanpa use, kita harus menulis new App\Payment\Gateway(). Konflik nama diselesaikan dengan alias:
use App\Payment\Gateway;
use External\Payment\Gateway as ExternalGateway;Memanggil require manual satu per satu tidak akan bertahan di proyek nyata. Solusinya: autoloading. Dengan PSR-4, PHP tahu cara memuat class hanya berdasarkan nama namespace-nya. Aturan PSR-4: namespace App\ dipetakan ke folder src/, sehingga App\Payment\Gateway otomatis dicari di src/Payment/Gateway.php.
Pendeklarasiannya dilakukan di composer.json (detail lengkap di episode 9):
{
"autoload": {
"psr-4": {
"App\\": "src/"
}
}
}Setelah itu jalankan composer dump-autoload dan panggil require "vendor/autoload.php"; sekali di entry point. Seluruh class yang dipakai akan dimuat otomatis — inilah yang membuat kode PHP modern bersih dari require_once berserakan.
Note
Autoloading bukan sekadar kenyamanan — ini fondasi ekosistem. Ketika kalian composer require laravel/framework, puluhan package termuat otomatis lewat mekanisme yang sama. Memahami PSR-4 berarti memahami cara kerja semua framework PHP.
Sebelum PHP 7, ada dua dunia terpisah: error (warning, notice, fatal) dan exception. Sejak PHP 7, hampir semua error berubah menjadi Throwable yang bisa ditangkap:
Throwable
├── Error (fatal error: parse, type, dsb.)
│ ├── TypeError
│ ├── ValueError
│ └── ...
└── Exception
└── RuntimeException, InvalidArgumentException, dsb.Perbedaan praktis: Error = sesuatu salah dengan kode kalian sendiri (panggil fungsi dengan tipe salah); Exception = kondisi luar yang perlu ditangani (file tidak ada, koneksi gagal).
try/catch/finally<?php
declare(strict_types=1);
function bacaFile(string $path): string
{
if (!is_readable($path)) {
throw new RuntimeException("File tidak bisa dibaca: $path");
}
return file_get_contents($path);
}
try {
$isi = bacaFile("/tmp/konfigurasi.txt");
echo $isi;
} catch (RuntimeException $e) {
echo "Gagal membaca: " . $e->getMessage() . "\n";
} catch (Throwable $e) {
echo "Terjadi kegagalan tak terduga\n";
} finally {
echo "Block ini selalu dijalankan.\n";
}try — blok yang dipantau.catch — penanganan per tipe exception; urut dari paling spesifik ke umum (Throwable terakhir).finally — selalu dieksekusi, baik sukses maupun gagal; tempat ideal untuk menutup koneksi/file.Exception khusus membuat penanganan lebih ekspresif dan log lebih informatif:
namespace App\Exception;
use RuntimeException;
class PaymentFailedException extends RuntimeException
{
public static function insufficientFunds(float $butuh, float $punya): self
{
return new self(
sprintf("Saldo tidak cukup: butuh %s, punya %s", $butuh, $punya)
);
}
}Lalu tangkap secara spesifik:
use App\Exception\PaymentFailedException;
try {
$payment->proses(100000);
} catch (PaymentFailedException $e) {
log_error($e->getMessage());
return response()->json(["error" => "Pembayaran gagal"], 402);
}Pola named constructor (self::insufficientFunds()) membuat pemanggilan ekspresif sekaligus memusatkan pesan error di satu tempat.
Untuk aplikasi web, pasang handler global agar error tidak pernah bocor mentah ke pengguna (detail keamanan di episode 17):
set_exception_handler(function (Throwable $e): void {
error_log($e->getMessage());
http_response_code(500);
echo "Terjadi kesalahan server.";
});
set_error_handler(function (int $level, string $message): bool {
throw new ErrorException($message, 0, $level);
});Dengan set_error_handler yang melempar ErrorException, semua warning PHP klasik ikut menjadi exception yang bisa ditangkap — inilah yang dimaksud "PHP 7+ menyatukan error dan exception".
Warning
Jangan menangkap exception lalu diam saja (catch (Throwable $e) {}). Paling sedikit log exception-nya dan beri respons yang jelas ke pengguna. Error yang ditelan adalah bug yang menunggu ledakan di waktu paling buruk.
declare(strict_types=1) — TypeError tidak muncul dan bug tersembunyi.Exception tapi fungsi melempar Error — gunakan Throwable bila ingin menangkap semua.try/catch untuk if/else biasa; exception itu mahal dan hanya untuk kondisi luar biasa.Inti yang harus dibawa pulang:
use menghindari konflik nama; autoloading PSR-4 menghilangkan require manual.Throwable menyatukan Error (bug kode) dan Exception (kondisi luar) sejak PHP 7.try/catch/finally dengan urutan catch paling spesifik ke umum.Di episode 9 selanjutnya kita mengoperasikan fondasi ekosistem: Composer & Autoloading — composer init/install/require, memahami composer.json dan composer.lock, semantic versioning, hingga composer audit untuk keamanan dependensi. Di sini kalian mulai membangun proyek seperti engineer profesional.