Closure, Callable & Generator

Fungsi anonim yang menangkap variabel (use), Closure::bind, callable dan first-class callable, serta generator (yield) untuk memproses data besar hemat memori.

Part 19 dari 22 ± 50 menit Gratis

Fungsi sebagai nilai

Di PHP fungsi bisa disimpan dalam variabel, dikirim sebagai argumen, dan dikembalikan dari fungsi lain. Fungsi tanpa nama ini disebut closure (objek dari class Closure).

$sapa = function (string $nama): string {
    return "Halo, $nama!";
};
echo $sapa('Budi');                  // Halo, Budi!

Menangkap variabel luar dengan use

Closure biasa tidak bisa melihat variabel di luarnya. Gunakan use untuk membawanya masuk:

$pajak = 0.11;
$hitung = function (int $harga) use ($pajak): float {
    return $harga * (1 + $pajak);
};
echo $hitung(100000);                // 111000
  • use ($x) menyalin nilai saat closure dibuat (perubahan di luar tidak ikut).
  • use (&$x) menangkap referensi sehingga perubahan terlihat dua arah.

Arrow function: versi ringkas

$hitung = fn (int $harga): float => $harga * (1 + $pajak);   // otomatis menangkap $pajak

Arrow function (fn) hanya berisi satu ekspresi dan menangkap variabel luar secara otomatis (nilainya).

Callable

Tipe callable menerima apa pun yang bisa dipanggil:

BentukContoh
Closure / arrow functionfn ($x) => $x * 2
Nama fungsi (string)'strtoupper'
Method objek[$objek, 'metode']
Method static['NamaClass', 'metode'] atau 'NamaClass::metode'
Objek dengan __invokenew Pengali(3)
First-class callable (PHP 8.1)strtoupper(...), $obj->metode(...)
function terapkan(array $data, callable $fn): array
{
    $hasil = [];
    foreach ($data as $item) {
        $hasil[] = $fn($item);
    }
    return $hasil;
}

print_r(terapkan([1, 2, 3], fn ($x) => $x ** 2));     // [1, 4, 9]
print_r(terapkan(['a', 'b'], strtoupper(...)));       // ['A', 'B']

Fungsi yang mengembalikan fungsi

function pengali(int $faktor): Closure
{
    return fn (int $x): int => $x * $faktor;
}

$kali5 = pengali(5);
echo $kali5(4);                     // 20

Teknik ini bisa dipakai untuk membuat filter, validator, atau middleware yang dapat dikonfigurasi.

Masalah: data terlalu besar

Bayangkan memproses berkas 5 juta baris. Jika semuanya dimuat ke array, memori habis. Generator menyelesaikannya: fungsi yang menghasilkan nilai satu per satu dan berhenti sementara di antara nilai.

yield

function angkaGenap(int $maks): Generator
{
    for ($i = 0; $i <= $maks; $i += 2) {
        yield $i;                    // serahkan nilai, lalu "tidur" sampai diminta lagi
    }
}

foreach (angkaGenap(10) as $n) {
    echo $n . ' ';                   // 0 2 4 6 8 10
}

Fungsi yang berisi yield otomatis mengembalikan objek Generator; kodenya baru berjalan saat di-foreach. Hanya satu nilai ada di memori pada satu waktu, jadi 1 juta atau 1 miliar angka pun tetap hemat.

Contoh nyata: membaca berkas besar

function bacaBaris(string $path): Generator
{
    $f = fopen($path, 'r');
    try {
        while (($baris = fgets($f)) !== false) {
            yield rtrim($baris, "\n");
        }
    } finally {
        fclose($f);
    }
}

foreach (bacaBaris('log.txt') as $no => $baris) { ... }

Key, yield from, dan send

function pasangan(): Generator
{
    yield 'a' => 1;                  // yield kunci => nilai
    yield 'b' => 2;
}

function gabung(): Generator
{
    yield 0;
    yield from [1, 2, 3];            // delegasikan ke array/generator lain
    yield 4;
}

iterator_to_array(gabung(), false);  // [0, 1, 2, 3, 4]

Generator juga bisa diurutkan lewat pipeline: satu generator memfilter hasil generator lain, tanpa pernah membuat array penuh.

function ambilGenap(iterable $sumber): Generator
{
    foreach ($sumber as $n) {
        if ($n % 2 === 0) {
            yield $n;
        }
    }
}

Kapan memakai apa?

KebutuhanPilih
Callback pendek satu ekspresiArrow function fn
Callback butuh beberapa barisClosure dengan use
Meneruskan fungsi yang sudah adaFirst-class callable nama(...)
Data besar / tak terbatasGenerator

Error umum

  • Undefined variable $x di dalam closure → lupa use ($x) (kecuali arrow function).
  • Generator hanya bisa dilewati sekali. Meng-foreach-nya lagi menghasilkan Exception: Cannot traverse an already closed generator.
  • Perubahan variabel setelah closure dibuat tidak terlihat → use menyalin nilai; pakai & bila perlu referensi.

Praktikkan langsung, gratis

Tulis dan jalankan kode langsung di browser, dapatkan penilaian otomatis. Daftar gratis kapan saja untuk menyimpan progres dan meraih sertifikat.

Coba latihan sekarang, tanpa daftar
Bagikan: WhatsApp Facebook LinkedIn X