Match (PHP 8.0+)

Ekspresi match sebagai switch modern dengan perbandingan ketat.

Daftar isi

Topik ini membahas ekspresi match yang diperkenalkan pada PHP 8.0 sebagai pemetaan nilai yang lebih ringkas daripada rangkaian if maupun switch warisan. Pembahasan mencakup bentuk dasarnya, perbandingan ketat yang membedakannya dari switch, penulisan beberapa kondisi sekaligus, serta idiom match(true) untuk menguji rentang nilai. Penanganan kondisi tanpa kecocokan dibahas pada bagian kesalahan umum karena bentuk kesalahannya khas.

Ekspresi match#

Ekspresi match membandingkan sebuah subjek dengan sejumlah kemungkinan nilai, lalu mengembalikan nilai dari kecocokan pertama. Setiap pasangan kemungkinan dan hasilnya disebut arm, ditulis dengan pola nilai => hasil, dan seluruh arm dibungkus kurung kurawal setelah kata kunci match. Karena match adalah ekspresi dan bukan pernyataan, hasilnya dapat langsung ditugaskan ke variabel sebagaimana contoh berikut.

php menu-catatan.php
<?php

$pilihan = 2;

$label = match ($pilihan) {
    1 => 'Buat catatan baru',
    2 => 'Buka catatan tersimpan',
    3 => 'Hapus catatan',
    default => 'Pilihan tidak dikenal',
};

echo "Menu $pilihan: $label", PHP_EOL;
text Keluaran
Menu 2: Buka catatan tersimpan

Bentuk di atas setara dengan rangkaian if dan elseif yang menugaskan $label pada setiap cabangnya, tetapi seluruh pemetaan terlihat dalam satu blok. Pernyataan break tidak diperlukan karena match tidak menembus ke arm berikutnya. Koma setelah arm terakhir diperbolehkan dan lazim dituliskan, sehingga penambahan arm baru tidak menuntut perubahan tanda baca.

Karena match adalah ekspresi, hasilnya tidak harus ditugaskan ke variabel terlebih dahulu. Nilai kembalian dapat dipakai langsung sebagai argumen fungsi, elemen array, maupun nilai yang dikembalikan fungsi. Sisi kanan arm juga boleh memuat ekspresi apa pun, misalnya perhitungan atau pemanggilan fungsi, sehingga pemetaan yang hasilnya harus dihitung tetap terangkum dalam satu blok.

Perbandingan ketat#

match membandingkan subjek dengan setiap arm menggunakan perbandingan ketat yang setara dengan operator ===, tanpa konversi tipe apa pun. Perilaku ini berbeda dari switch, yaitu pernyataan percabangan warisan yang membandingkan satu nilai dengan sejumlah case secara lemah, sehingga string '200' pada switch cocok dengan case bernilai 200. Pada match, keduanya dianggap berbeda.

php ketat-tipe.php
<?php

$kode = '200'; // string, bukan int

$label = match ($kode) {
    200 => 'Cocok dengan int 200',
    '200' => 'Cocok dengan string 200',
    404 => 'Tidak ditemukan',
    default => 'Kode tidak dikenal',
};

echo $label, PHP_EOL;
text Keluaran
Cocok dengan string 200

Arm int 200 dilewati karena subjeknya bertipe string, dan kecocokan baru ditemukan pada arm '200'. Apabila contoh yang sama ditulis dengan switch, string '200' langsung cocok dengan case 200 yang tercantum lebih dulu, sehingga ketidaksesuaian tipe tidak terlihat. Perbandingan ketat membuat kesalahan tipe segera tampak pada hasil match.

Ekspresi subjek dievaluasi satu kali sebelum perbandingan dimulai, kemudian seluruh arm diperiksa berurutan dari atas ke bawah sampai kecocokan pertama ditemukan. Arm yang tersisa tidak diuji lagi, sehingga arm yang paling sering cocok sebaiknya diletakkan lebih dulu agar pemeriksaan yang tidak diperlukan berkurang.

Beberapa kondisi dan match(true)#

Satu arm boleh memuat beberapa kondisi yang dipisahkan koma, dan kecocokan terjadi bila salah satu kondisinya bernilai sama dengan subjek. Pola ini meringkas beberapa arm yang hasilnya identik menjadi satu baris. Bentuk khususnya adalah match(true), yaitu match yang subjeknya sengaja berupa true sehingga setiap arm memuat ekspresi boolean yang diuji berurutan. Pola ini paling sering digunakan untuk rentang nilai.

php predikat-match.php
<?php

$nilai = 86;

$predikat = match (true) {
    $nilai < 0, $nilai > 100 => 'Di luar rentang',
    $nilai >= 90 => 'Sangat baik',
    $nilai >= 80 => 'Baik',
    $nilai >= 70 => 'Cukup',
    default => 'Perlu bimbingan',
};

echo "Nilai: $nilai", PHP_EOL;
echo "Predikat: $predikat", PHP_EOL;
text Keluaran
Nilai: 86
Predikat: Baik

Arm pertama memeriksa nilai di luar rentang 0 sampai 100 dengan dua kondisi dalam satu arm, dan pemeriksaan itu sengaja diletakkan paling atas. Bila arm $nilai >= 90 diletakkan lebih dulu, angka 105 akan langsung memenuhinya dan predikat Di luar rentang tidak pernah tercetak. Urutan arm pada match(true) berperan sama seperti urutan kondisi pada rangkaian elseif, yaitu evaluasi berhenti pada kecocokan pertama.

Kondisi yang dipisahkan koma pada satu arm berperan seperti case yang ditumpuk pada switch, tetapi tanpa risiko penembusan yang tidak disengaja. Setiap kondisi dibandingkan dengan subjek menggunakan perbandingan ketat yang sama, dan bila salah satu sama, arm tersebut langsung menghasilkan nilai. Pola ini paling berguna ketika beberapa masukan berbeda perlu dipetakan ke satu hasil yang sama, misalnya kode menu atau singkatan hari.

Kesalahan umum#

Error tersebut bukan peringatan yang bisa diabaikan, melainkan exception, yaitu error berupa objek yang dapat ditangkap dengan try dan catch. Contoh berikut membungkus match dalam try dan catch agar pesannya dapat ditampilkan tanpa menghentikan program.

php lupa-default.php
<?php

$kode = 302;

try {
    $label = match ($kode) {
        200 => 'Sukses',
        404 => 'Tidak ditemukan',
        500 => 'Kesalahan server',
    };
    echo $label, PHP_EOL;
} catch (UnhandledMatchError $e) {
    echo 'Error: ', $e->getMessage(), PHP_EOL;
}
text Keluaran
Error: Unhandled match case 302

Kesalahan kedua adalah mengira perbandingan match bersifat lemah seperti switch. Bila subjek berasal dari masukan yang tipe datanya belum pasti, misalnya string dari URL, konversi eksplisit seperti (int) atau pemeriksaan tipe dilakukan terlebih dahulu sebelum subjek dibandingkan dengan arm int. Kebiasaan ini memastikan perbandingan ketat tetap berlaku.

Kesalahan ketiga adalah memakai match di atas versi PHP yang lebih tua. Parser PHP 7 tidak mengenal kata kunci match, sehingga berkasnya gagal dimuat sama sekali dan bukan sekadar berperilaku berbeda. Versi minimum proyek dicantumkan dan diperiksa sebelum fitur ini digunakan.

Ringkasan#

  • match adalah ekspresi yang mengembalikan nilai dari arm pertama yang cocok dan tidak memerlukan break.
  • Perbandingannya ketat setara dengan ===, sehingga string '200' tidak cocok dengan int 200.
  • Satu arm boleh memuat beberapa kondisi yang dipisahkan koma, dan match(true) menguji ekspresi boolean secara berurutan untuk pola rentang nilai.
  • Subjek tanpa kecocokan pada match tanpa default melempar UnhandledMatchError.

Referensi#