PHP 8.0, dirilis November 2020, memanjakan kita dengan rangkaian fitur sekaligus: union types, match, nullsafe operator, constructor promotion, dan named arguments. Fitur yang terakhir ini punya efek paling luas terhadap kode sehari-hari, karena hampir semua baris program adalah pemanggilan fungsi atau method. Sintaks dasarnya — namaParameter: nilai — sudah kita bahas tuntas pada chapter named arguments di Section Fungsi
. Chapter ini mengambil sudut pandang evolusi: masalah apa yang selama puluhan tahun ditanggung fungsi bawaan PHP berparameter panjang, bagaimana named arguments bersinergi dengan fitur 8.0 lainnya seperti constructor promotion dan attributes, serta konsekuensi desain API yang dibawanya.
Luka Lama: Fungsi Bawaan Berparameter Panjang #
Fungsi bawaan PHP banyak yang lahir sebelum era desain API modern: daftar parameternya panjang, parameter penting tersembunyi di posisi belakang, dan nilai default-nya harus disalin dari dokumentasi. Contoh klasiknya array_slice() — parameter keempatnya adalah saklar preserve_keys yang menjaga kunci array tetap utuh. Bandingkan dua gaya pemanggilan berikut:
<?php
$data = ['satu', 'dua', 'tiga', 'empat'];
// Gaya PHP 7 dan sebelumnya: makna `null` dan `true` harus diterka
$lama = array_slice($data, 1, null, true);
// Gaya PHP 8.0+: maksud tersurat di pemanggilan
$baru = array_slice($data, 1, preserve_keys: true);
var_dump($lama === $baru);
print_r($baru);Output yang Dihasilkan:
bool(true)
Array
(
[1] => dua
[2] => tiga
[3] => empat
)Kedua pemanggilan menghasilkan array yang identik — terbukti dari bool(true); print_r menegaskan kunci array tetap 1 sampai 3, tidak diindeks ulang dari nol. Bedanya ada pada kejelasan: pembaca kode versi pertama harus menebak apa arti null (parameter $length yang sengaja dilewati agar defaultnya terpakai) dan true (saklar $preserve_keys). Pada versi kedua, preserve_keys: true menyatakan maksudnya sendiri, dan parameter yang tidak relevan cukup dilompati.
Pola yang sama berlaku pada banyak fungsi bawaan lain:
| Fungsi bawaan | Sebelum PHP 8.0 | Sejak PHP 8.0 |
|---|---|---|
array_slice() | array_slice($a, 1, null, true) | array_slice($a, 1, preserve_keys: true) |
htmlspecialchars() | htmlspecialchars($s, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8', false) | htmlspecialchars($s, double_encode: false) |
round() | round($phi, 2) | round($phi, precision: 2) |
Penjelasan lengkap contoh htmlspecialchars() dan round() tersedia pada chapter di Section Fungsi
; prinsipnya satu: named arguments menjangkau parameter di kedalaman daftar tanpa menyalin nilai default parameter di depannya.
Aturan Posisi Sesudah Bernama #
Satu aturan sintaks yang wajib melekat: argument posisional boleh mendahului argument bernama, tetapi tidak boleh menyusul setelahnya. Urutan membaca harus selaras dengan urutan parameter:
<?php
function susunMenu(string $judul, string $ikon = 'box'): string
{
return "$judul ($ikon)";
}
echo susunMenu(ikon: 'chart', 'Laporan');Output yang Dihasilkan:
Fatal error: Cannot use positional argument after named argument in /home/z/my-project/php-course/content/php/modern-php/named-arguments/.verify_tmp.php on line 7Pemanggilan di atas berakhir Fatal error: Cannot use positional argument after named argument — interpreter menolak menebak posisi argument posisional yang muncul setelah argument bernama. Aturan ini menjaga ketakterambiguan: begitu sebuah parameter diisi lewat nama, posisi berikutnya tidak lagi bisa dipetakan secara pasti.
Bersinergi dengan Constructor Promotion #
Dua fitur besar PHP 8.0 ini memang lahir berpasangan. Constructor promotion memampatkan deklarasi property sekaligus parameter constructor, dan named arguments membuat pembuatan object konfigurasi terbaca seperti daftar opsi. Perhatikan class koneksi database berikut:
<?php
class KoneksiDb
{
public function __construct(
private string $host = 'localhost',
private int $port = 3306,
private string $namaDb = 'app',
) {}
public function deskripsi(): string
{
return "mysql:host={$this->host};port={$this->port};dbname={$this->namaDb}";
}
}
$default = new KoneksiDb();
$cabang = new KoneksiDb(host: 'db.cabang.example.com', namaDb: 'toko');
echo $default->deskripsi(), "\n";
echo $cabang->deskripsi(), "\n";Output yang Dihasilkan:
mysql:host=localhost;port=3306;dbname=app
mysql:host=db.cabang.example.com;port=3306;dbname=tokoMari kita bedah bagian-bagian pentingnya:
- Baris 4-7 (constructor promotion): tiga parameter sekaligus menjadi property
private— mekanisme promotion yang dibahas tuntas pada chapter constructors . Semua parameternya punya nilai default, sehingga object bisa dibuat tanpa argument apa pun. - Baris 15 (
new KoneksiDb()): semua default terpakai — koneksi kelocalhost:3306dengan databaseapp. - Baris 16 (
new KoneksiDb(host: ..., namaDb: ...)): hanya dua parameter yang diubah;$portmemakai default tanpa perlu ditulis. Tanpa named arguments, kita harus menyisipkan3306secara manual di tengah hanya untuk sampai ke$namaDb.
Pola new Opsi(host: ..., namaDb: ...) seperti inilah yang menggantikan kebiasaan lama mengirim array opsi (['host' => ..., 'dbname' => ...]) — array tidak divalidasi dan tidak didukung editor, sedangkan named arguments diperiksa interpreter terhadap signature aslinya.
Named Arguments pada Function Variadic #
Function variadic — parameter ...$nama yang menampung argument sisa — berinteraksi dengan cara khusus: argument bernama yang jatuh ke parameter variadic menjadi elemen array dengan kunci string. Perhatikan pembangun URL berikut:
<?php
function buatUrl(string $path, ...$query): string
{
$pasangan = [];
foreach ($query as $nama => $nilai) {
$pasangan[] = "$nama=$nilai";
}
return $path . ($pasangan === [] ? '' : '?' . implode('&', $pasangan));
}
echo buatUrl('/produk'), "\n";
echo buatUrl('/produk', halaman: 2, urutkan: 'murah'), "\n";Output yang Dihasilkan:
/produk
/produk?halaman=2&urutkan=murahPemanggilan pertama tidak mengirim query sama sekali, sehingga $query berupa array kosong dan hasilnya /produk tanpa tanda tanya. Pemanggilan kedua mengirim halaman: 2 dan urutkan: 'murah'; di dalam function, $query bernilai ['halaman' => 2, 'urutkan' => 'murah'] — nama parameter menjadi kunci array secara otomatis, dan loop foreach mengubahnya menjadi string query halaman=2&urutkan=murah.
Unpacking Array Asosiatif menjadi Argument #
Sebelum PHP 8.1, operator spread ...$array hanya boleh memuat array ber-kunci integer. PHP 8.1 melonggarkan aturannya: kunci string kini menjadi nama parameter. Fitur ini melengkapi named arguments karena konfigurasi yang tersimpan sebagai array asosiatif bisa langsung disebarkan ke pemanggilan function:
<?php
function buatPesan(string $ke, string $isi, bool $penting = false): string
{
return ($penting ? '[PENTING] ' : '') . "$ke: $isi";
}
$argumen = ['isi' => 'Rapat pukul 09.00', 'ke' => 'Budi'];
echo buatPesan(...$argumen), "\n";
$argumenPenting = ['ke' => 'Siti', 'isi' => 'Laporan siang ini', 'penting' => true];
echo buatPesan(...$argumenPenting), "\n";Output yang Dihasilkan:
Budi: Rapat pukul 09.00
[PENTING] Siti: Laporan siang iniPerhatikan bahwa urutan kunci pada $argumen (isi sebelum ke) tidak mengikuti urutan parameter ($ke sebelum $isi) — named arguments menuntut nama yang benar, bukan urutan yang benar. Kunci penting => true pada array kedua pun diterima sebagai argument bernama $penting.
Sinergi dengan Attributes #
Attributes, fitur 8.0 yang menempelkan metadata terstruktur pada deklarasi, memakai sintaks argument yang sama persis — dan justru di sinilah named arguments paling menonjol, karena daftar opsi attribute biasa panjang dan jarang diisi semua. Contoh berikut mendeklarasikan attribute Route lalu membacanya kembali lewat Reflection:
<?php
#[Attribute]
class Route
{
public function __construct(
public string $path,
public array $methods = ['GET'],
) {}
}
class ControllerProduk
{
#[Route(path: '/produk', methods: ['GET', 'POST'])]
public function daftar(): array
{
return ['buku', 'pulpen'];
}
}
$refleksi = new ReflectionMethod(ControllerProduk::class, 'daftar');
$atribut = $refleksi->getAttributes(Route::class)[0]->newInstance();
echo $atribut->path, ' [', implode(', ', $atribut->methods), "]\n";Output yang Dihasilkan:
/produk [GET, POST]Deklarasi #[Route(path: '/produk', methods: ['GET', 'POST'])] membaca seperti konfigurasi: opsi path wajib diisi, opsi methods menimpa default ['GET']. Framework modern membaca metadata semacam ini lewat ReflectionMethod — baris terakhir membuktikan nilainya tersimpan utuh. Dokumentasi lengkap attributes ada di php.net
.
Mengganti Nama Parameter Adalah Perubahan Merusak #
Semua kemudahan di atas membeli satu tanggung jawab baru: nama parameter kini bagian dari kontrak publik API. Pengelola library yang mengganti nama parameter bisa merusak kode penggunanya tanpa menyentuh isi function sama sekali. Simulasikan skenarionya: versi 1.0 dari sebuah library merilis function berikut, lalu versi 2.0 mengganti nama $jumlah menjadi $nilai:
<?php
function formatUang(int $jumlah, string $mataUang = 'IDR'): string
{
return "$mataUang $jumlah";
}
// Pemanggil menulis kode saat library masih versi 1.0
echo formatUang(nilai: 50000);Output yang Dihasilkan:
Fatal error: Uncaught Error: Unknown named parameter $nilai in /home/z/my-project/php-course/content/php/modern-php/named-arguments/.verify_tmp.php:8
Stack trace:
#0 {main}
thrown in /home/z/my-project/php-course/content/php/modern-php/named-arguments/.verify_tmp.php on line 8Pemanggilan tersebut gagal dengan Fatal error: Unknown named parameter $nilai — parameter bernama $nilai tidak dikenal karena versi terpasang masih menyebutnya $jumlah. Perhatikan bahwa dokumen migrasi library mungkin hanya menulis “isi function tidak berubah”; bagi pemanggil yang memakai named arguments, perubahan ini sama merusaknya dengan penghapusan function.
Ringkasan #
Named arguments menuntaskan luka desain lama fungsi bawaan PHP: parameter penting di posisi dalam kini dijangkau lewat nama, argument posisional tetap boleh mendahului asalkan tidak menyusul, dan pemanggilan new menjadi terbaca seperti daftar opsi berkat sinergi dengan constructor promotion. Perilakunya meluas ke function variadic — nama menjadi kunci array — dan di PHP 8.1 ke operator spread pada array asosiatif. Harganya satu: nama parameter menjadi API publik, sehingga penggantian nama adalah perubahan merusak. Fitur 8.0 lainnya mengambil jalan berbeda untuk memodernkan alur kontrol — match expression, topik chapter berikutnya di section ini.