Variadik dan Arrow Function

Parameter variadik ...$args dan closure pendek fn().

Daftar isi

Jumlah argumen sebuah fungsi tidak selalu dapat ditetapkan di depan, dan tidak setiap fungsi pembanding perlu ditulis panjang. Topik ini membahas parameter variadik dengan notasi ..., yaitu fungsi yang menerima argumen dalam jumlah bebas, serta arrow function dengan kata kunci fn(), yaitu closure pendek untuk satu ekspresi. Setelah topik ini dibaca, fungsi penghitung dengan masukan fleksibel dan fungsi pembanding ringkas dapat ditulis dengan benar.

Parameter variadik#

Parameter variadik dinyatakan dengan mengawali nama parameter terakhir dengan tiga tanda titik, seperti ...$nilai. PHP mengumpulkan seluruh argumen tambahan menjadi satu array terurut yang dapat diakses di dalam tubuh fungsi. Parameter variadik wajib ditempatkan paling akhir karena argumen yang mendahuluinya tetap dipetakan ke parameter masing-masing, sedangkan seluruh sisa argumen dikumpulkan oleh parameter variadik.

Deklarasi tipe tetap berlaku pada parameter variadik, dan tipe itu diperiksa pada setiap argumen yang diterima. Dengan demikian, int|float ...$nilai menolak argumen string sama seperti parameter tunggal. Apabila fungsi dipanggil tanpa argumen sama sekali, hasil pengumpulan berupa array kosong, sehingga tubuh fungsi perlu menangani kasus tersebut sebelum menghitung rata-rata atau nilai minimum.

Skrip berikut menghitung rata-rata nilai ujian dengan fungsi variadik. Tiga panggilan pertama menggunakan argumen biasa, termasuk panggilan tanpa argumen, sedangkan panggilan keempat menyebarkan isi array menjadi argumen melalui notasi titik tiga pada titik pemanggilan.

php rekap-nilai.php
<?php
declare(strict_types=1);

function rataRata(int|float ...$nilai): float
{
    if ($nilai === []) {
        return 0.0;
    }
    return array_sum($nilai) / count($nilai);
}

echo rataRata(80, 75, 90, 85), "\n";
echo rataRata(70.5), "\n";
echo rataRata(), "\n";

$daftar = [88, 92, 79];
echo rataRata(...$daftar), "\n";
text Keluaran
82.5
70.5
0
86.333333333333

Panggilan tanpa argumen menghasilkan nol, bukan error, karena pemeriksaan $nilai === [] menutup kasus tersebut secara eksplisit. Tanpa pemeriksaan itu, pembagian oleh count($nilai) yang bernilai nol memicu peringatan pembagian oleh nol. Pola semacam ini layak disalin untuk setiap fungsi variadik yang menghitung agregasi, seperti nilai minimum, maksimum, atau gabungan teks.

Pemanggilan rataRata(...$daftar) disebut penyebaran argumen (argument unpacking), yaitu kebalikan dari parameter variadik. Notasi ... yang sama melayani dua arah, sehingga penulisannya konsisten antara deklarasi dan titik pemanggilan.

Arrow function#

Arrow function adalah bentuk closure, yakni fungsi tanpa nama, dengan sintaks paling pendek di PHP. Bentuknya adalah kata kunci fn, daftar parameter, tanda =>, lalu satu ekspresi yang nilainya otomatis menjadi nilai kembalian. Karena itu, kata kunci return dan tanda kurung kurawal tidak ditulis. Deklarasi tipe parameter dan tipe kembalian tetap dapat disertakan, misalnya fn(int $n): int => $n * $n.

Bentuk pendek ini paling berguna sebagai callback, yaitu fungsi yang diteruskan sebagai argumen ke fungsi lain. Fungsi pengolah array seperti array_map(), array_filter(), dan usort() memanggil callback tersebut untuk setiap elemen, sehingga logika perubahan, penyaringan, dan pembandingnya dituliskan langsung di titik pemanggilan. Jumlah parameter pada arrow function boleh nol, sehingga bentuk fn(): int => 42 sah untuk callback yang tidak memerlukan masukan. Tipe pada parameter dan kembalian juga dapat ditiadakan, meskipun menuliskannya menjaga konsistensi dengan gaya fungsi lain pada proyek. Ekspresi yang memuat pilihan sederhana dapat dituliskan dengan operator ternary, sehingga sebagian logika bersyarat tetap muat dalam satu baris.

Skrip berikut menggunakan tiga arrow function untuk mengubah, menyaring, dan mengurutkan satu array angka. Pembanding pada usort() mengembalikan hasil operator <=>, sehingga urutannya menjadi menurun.

php pengubah-daftar.php
<?php
declare(strict_types=1);

$daftar = [3, 1, 4, 1, 5, 9];

$kuadrat = array_map(fn(int $n): int => $n * $n, $daftar);
echo implode(', ', $kuadrat), "\n";

$genap = array_values(array_filter($daftar, fn(int $n): bool => $n % 2 === 0));
echo implode(', ', $genap), "\n";

usort($daftar, fn(int $a, int $b): int => $b <=> $a);
echo implode(', ', $daftar), "\n";
text Keluaran
9, 1, 16, 1, 25, 81
4
9, 5, 4, 3, 1, 1

Menangkap variabel dari lingkup luar#

Arrow function otomatis menangkap variabel yang digunakan dari lingkup luar dengan cara menyalin nilainya, tanpa kata kunci tambahan. Closure biasa tidak bekerja demikian, karena fungsi tanpa nama yang dideklarasikan dengan function hanya dapat mengakses variabel luar yang disebutkan secara eksplisit pada klausul use. Perbedaan ini menjadikan fn lebih ringkas, sedangkan klausul use membuat daftar ketergantungan tertulis pada baris deklarasi.

Penyalinan nilai terjadi pada saat definisi, bukan pada saat pemanggilan, sehingga perubahan variabel luar setelah definisi tidak terlihat oleh closure. Perilaku ini penting dipahami karena terlihat seperti bug pada kode yang mengubah nilai variabel luar di tengah program. Apabila nilai terbaru memang dikehendaki, klausul use (&$nama) pada closure biasa menangkap variabel melalui referensi, atau nilai yang berubah diteruskan sebagai parameter.

Skrip berikut mendefinisikan arrow function dan closure biasa dengan nilai diskon yang sama, lalu mengubah nilai diskon tersebut. Panggilan ketiga tetap menghasilkan potongan lama karena kedua fungsi memegang salinan nilai dari saat definisi.

php diskon-arrow.php
<?php
declare(strict_types=1);

$diskon = 0.1;

$hargaDiskon = fn(float $harga): float => $harga * (1 - $diskon);

$hargaDiskonLama = function (float $harga) use ($diskon): float {
    return $harga * (1 - $diskon);
};

echo $hargaDiskon(200.0), "\n";
echo $hargaDiskonLama(200.0), "\n";

$diskon = 0.2;
echo $hargaDiskon(200.0), "\n";
text Keluaran
180
180
180

Pemilihan antara keduanya mengikuti panjang logikanya. Ekspresi tunggal yang maksudnya jelas layak ditulis sebagai arrow function, sedangkan logika yang memuat percabangan atau lebih dari satu langkah lebih aman pada closure biasa, karena tubuh closure memuat pernyataan lengkap. Keduanya menghasilkan objek dari kelas Closure yang sama, sehingga keduanya diterima oleh fungsi mana pun yang menerima callable.

Kesalahan umum#

  • Menempatkan parameter variadik bukan pada posisi terakhir. Deklarasi seperti function gabung(...$potongan, string $pemisah) gagal dijalankan karena argumen setelah variadik tidak pernah terpetakan. Pindahkan parameter variadik ke posisi terakhir pada deklarasi. Penamaan ...$args yang biasa muncul pada contoh hanyalah kebiasaan, dan nama parameter bebas disesuaikan dengan makna isinya.
  • Menulis lebih dari satu ekspresi pada arrow function. Bentuk fn hanya memuat satu ekspresi, sehingga pernyataan bersyarat atau perulangan tidak dapat dituliskan di dalamnya. Bila logikanya lebih panjang, gunakan closure biasa dengan tubuh fungsi lengkap. Kata kunci use juga tidak dikenali oleh sintaks fn, sehingga penggabungan keduanya menghasilkan error sintaks.
  • Mengharapkan arrow function melihat perubahan terbaru. Penyalinan nilai terjadi saat definisi, sehingga pembaruan variabel luar sesudahnya tidak terbawa. Teruskan nilai terbaru sebagai parameter atau gunakan use (&$variabel) bila referensi memang diperlukan.
  • Mengira parameter variadik selalu berupa array terindeks. Pemanggilan dengan argumen bernama pada fungsi variadik menempatkan nilai tersebut sebagai entri berkunci string, sehingga count() dan array_sum() tetap bekerja, tetapi pengambilan nilai melalui indeks numerik tidak dapat dilakukan. Pilih salah satu gaya pemanggilan untuk satu fungsi agar isi array-nya dapat diprediksi.

Ringkasan#

  • Parameter variadik ...$nilai mengumpulkan sisa argumen menjadi satu array, wajib ditempatkan terakhir, dan deklarasi tipenya diperiksa pada setiap argumen.
  • Notasi ... pada titik pemanggilan menyebarkan isi array menjadi argumen, sebagai kebalikan dari pengumpulan parameter variadik.
  • Arrow function fn adalah closure satu ekspresi dengan nilai kembalian otomatis dan sangat sesuai untuk callback pengolah array.
  • Arrow function menangkap variabel luar secara otomatis dengan penyalinan nilai saat definisi, sedangkan closure biasa memerlukan klausul use.

Referensi#