Semua fungsi yang telah kita tulis sejauh ini punya nama, dan nama itulah yang dipakai untuk memanggilnya. Namun sering kali logika hanya dibutuhkan sekali: kriteria pengurutan untuk satu daftar, transformasi untuk satu array, atau blok hitung-hitungan yang langsung dijalankan. Untuk kebutuhan semacam itu PHP memperlakukan fungsi sebagai nilai — function yang dibuat tanpa nama, disimpan ke dalam variabel, dikirim sebagai argument, lalu dipanggil kapan pun diperlukan. Pada Chapter ini kita pelajari bentuk dasarnya, fakta bahwa setiap anonymous function sebenarnya adalah object Closure, pola pemakaian sebagai callback, hingga batas scope yang membuka jalan menuju closure.
Function sebagai Nilai #
Membuat anonymous function mirip dengan mendefinisikan fungsi biasa, hanya tanpa nama dan diakhiri titik koma — karena konstruksi ini adalah penugasan nilai, sama seperti $harga = 50000;. Variabel yang menerima fungsi tersebut selanjutnya bisa dipanggil seperti fungsi bernama. Mari kita buktikan juga bahwa nilai yang disimpan bukan sekadar “resep”, melainkan object sungguhan:
<?php
$sapa = function (string $nama): string {
return "Halo, $nama!";
};
echo $sapa("Budi") . "\n";
echo get_class($sapa) . "\n";
var_dump($sapa instanceof Closure);Output yang Dihasilkan:
Halo, Budi!
Closure
bool(true)Mari kita telaah baris-barisnya:
function (string $nama): string { ... }menghasilkan nilai berupa fungsi; variabel$sapakini menunjuk ke fungsi tersebut.- Pemanggilan memakai bentuk
$sapa("Budi")— tanda kurung setelah variabel berarti “jalankan fungsi yang tersimpan di dalam variabel ini”. get_class($sapa)mengembalikanClosure, dan pemeriksaan$sapa instanceof Closuremenghasilkanbool(true).
Callback Pengurutan untuk usort #
Pemakaian paling khas anonymous function adalah callback — fungsi yang dikirim sebagai argument untuk fungsi lain. Contoh primernya usort(), yang bertugas mengurutkan array tetapi tidak mengetahui aturan urutannya; aturan itu kita pasok lewat callback dengan kontrak: kembalikan angka negatif bila elemen pertama harus berada di depan, positif bila harus di belakang, dan nol bila keduanya setara. Operator spaceship <=> mempermudah kontrak ini karena menghasilkan tepat -1, 0, atau 1:
<?php
$produk = [
["nama" => "Laptop", "harga" => 8500000],
["nama" => "Mouse", "harga" => 150000],
["nama" => "Monitor", "harga" => 2200000],
];
usort($produk, function (array $a, array $b): int {
return $a["harga"] <=> $b["harga"];
});
foreach ($produk as $produkItem) {
echo $produkItem["nama"] . ": Rp" . $produkItem["harga"] . "\n";
}Output yang Dihasilkan:
Mouse: Rp150000
Monitor: Rp2200000
Laptop: Rp8500000Mari kita bedah cara kerjanya:
- Callback menerima dua elemen
$adan$b— dua baris yang sedang dibandingkan olehusort()— dengan return typeintsesuai kontrak. $a["harga"] <=> $b["harga"]bernilai-1bila harga$alebih kecil,1bila lebih besar, dan0bila sama.usort()memanggil callback ini berulang kali hingga seluruh array terurut — hasilnya naik dari Mouse termurah sampai Laptop termahal.
Inilah alasan anonymous function lahir: aturan urut “harga termurah dulu” hanya relevan untuk array ini, jadi tidak ada gunanya memenuhi scope global dengan fungsi bernama bandingkanHarga() yang dipakai satu kali.
Pola IIFE #
Anonymous function juga bisa langsung dijalankan pada saat dibuat — pola yang dikenal sebagai IIFE (Immediately Invoked Function Expression). Caranya: bungkus definisi dengan tanda kurung agar menjadi ekspresi utuh, lalu tempelkan tanda kurung pemanggilan beserta argument di belakangnya. Pola ini berguna membungkus perhitungan sementara agar tidak menetap di scope global:
<?php
$totalBelanja = 250000;
$kembalian = (function (int $uangDibayar, int $total): int {
return $uangDibayar - $total;
})(300000, $totalBelanja);
echo "Kembalian: Rp$kembalian\n";Output yang Dihasilkan:
Kembalian: Rp50000Mari kita bedah konstruksinya:
(function (int $uangDibayar, int $total): int { ... })— tanda kurung pembungkus mengubah definisi fungsi menjadi ekspresi yang bisa langsung dipanggil.(300000, $totalBelanja)pada ekor konstruksi memanggil fungsi tersebut; nilai kembaliannya disimpan ke$kembalian.- Setelah baris ini selesai, fungsi beserta variabel lokalnya hilang — tidak ada sisa di scope global.
array_map dan array_filter dengan Anonymous Function #
Dua fungsi array paling sering berpasangan dengan anonymous function. array_map() menerapkan sebuah transformasi ke setiap elemen dan mengembalikan array hasil transformasi; array_filter() menyimpan hanya elemen yang membuat callback mengembalikan true. Keduanya menerima callback sebagai argument terakhir:
<?php
$hargaProduk = [50000, 125000, 80000, 300000];
$hargaDiskon = array_map(function (int $harga): int {
return (int) round($harga * 0.9);
}, $hargaProduk);
$hargaPremium = array_filter($hargaProduk, function (int $harga): bool {
return $harga >= 100000;
});
echo "Setelah diskon : " . implode(", ", $hargaDiskon) . "\n";
echo "Harga premium : " . implode(", ", $hargaPremium) . "\n";Output yang Dihasilkan:
Setelah diskon : 45000, 112500, 72000, 270000
Harga premium : 125000, 300000Callback pertama memotong setiap harga sebesar 10% lalu membulatkannya; array_map() menjaga urutan dan jumlah elemen tetap empat. Callback kedua menguji $harga >= 100000, dan hanya dua elemen yang lolos. Satu detail yang sering mengejutkan: array_filter() mempertahankan key asli — bila elemen di tengah tersaring, array hasil memiliki lompatan pada indeksnya dan tidak diindeks ulang. Bila Anda butuh indeks berurutan 0, 1, 2, …, bungkus hasilnya dengan array_values().
Dinding Scope Tanpa Auto-Capture #
Kita tutup dengan batasan yang menentukan arah Chapter berikutnya: tubuh anonymous function punya scope sendiri. Variabel di luar fungsi tidak otomatis terlihat di dalamnya — PHP sengaja menjaga dinding scope ini agar fungsi tidak diam-diam bergantung pada keadaan sekitarnya. Lihat apa yang terjadi bila kita lupa:
<?php
$persenDiskon = 0.1;
$hitungDiskon = function (float $harga): float {
return $harga * $persenDiskon;
};
echo $hitungDiskon(200000) . "\n";Saat dijalankan, PHP memunculkan Warning: Undefined variable $persenDiskon dari dalam fungsi, lalu baris terakhir mencetak 0 — $persenDiskon yang tak terlihat dianggap bernilai null, dan 200000 * null menghasilkan 0. Tidak ada error fatal; program terus berjalan dengan nilai yang salah, dan diam-diam seperti inilah bug scope biasanya masuk. Solusinya adalah mendaftarkan variabel luar yang dibutuhkan lewat klausa use():
<?php
$persenDiskon = 0.1;
$hitungDiskon = function (float $harga) use ($persenDiskon): float {
return $harga * $persenDiskon;
};
echo $hitungDiskon(200000) . "\n";Output yang Dihasilkan:
20000Klausa use ($persenDiskon) menyalin nilai variabel luar ke dalam fungsi pada saat fungsi dibuat, sehingga callback kini menghasilkan 20000. Perhatikan bahwa use() tetap tidak membuka seluruh scope global — hanya variabel yang disebut secara eksplisit yang ikut masuk. Mekanisme penangkapan ini adalah jantung dari closure, dan kita bedah tuntas aturan mainnya — by value, by reference, kapan salinan diambil — pada Chapter Closures
.
Ringkasan #
Anonymous function menjadikan fungsi sebagai nilai: disimpan dalam variabel, dikirim sebagai callback untuk usort(), array_map(), dan array_filter(), dijalankan lewat pola IIFE, dan selalu terwujud sebagai object Closure. Batasannya pun jelas — tubuhnya memiliki scope sendiri dan tidak melihat variabel luar tanpa klausa use(). Jembatan itulah yang mengangkat anonymous function menjadi closure utuh, topik yang kita bedah pada Chapter berikutnya.