Switch dan Perulangan

Switch warisan serta perulangan for, while, dan foreach.

Daftar isi

Topik ini membahas switch sebagai bentuk percabangan warisan (legacy) beserta pernyataan break yang menyertainya, lalu beralih ke perulangan for, while, do-while, dan foreach. Pengendalian perulangan dengan break dan continue dibahas bersama contoh for, dan bagian akhir menyingkap jebakan referensi pada foreach beserta cara memutusnya. Setelah topik ini dipelajari, struktur perulangan yang tepat untuk sebuah tugas dapat dipilih dengan alasan yang jelas.

Switch warisan dan fallthrough#

Pernyataan switch membandingkan sebuah ekspresi dengan sejumlah case, yaitu label nilai yang diuji, menggunakan perbandingan lemah yang setara dengan operator ==. Bila nilai keduanya sama, seluruh pernyataan pada case itu dijalankan sampai ditemukan break yang menghentikan switch. Bila break tidak dituliskan, eksekusi menembus ke case berikutnya, dan perilaku ini disebut fallthrough. Cabang yang menampung sisanya dituliskan sebagai default.

php kategori-hari.php
<?php

$hari = 'Sabtu';

switch ($hari) {
    case 'Senin':
    case 'Selasa':
    case 'Rabu':
    case 'Kamis':
    case 'Jumat':
        $kategori = 'Hari kerja';
        break;
    case 'Sabtu':
    case 'Minggu':
        $kategori = 'Akhir pekan';
        break;
    default:
        $kategori = 'Nama hari tidak dikenal';
        break;
}

echo "$hari: $kategori", PHP_EOL;
text Keluaran
Sabtu: Akhir pekan

Case Senin sampai Jumat dituliskan bertumpuk tanpa isi, sehingga kelimanya jatuh ke satu blok yang sama. Inilah penggunaan fallthrough yang disengaja, yaitu memetakan beberapa masukan ke satu hasil. Bila case dan hasilnya berpasangan satu-satu, setiap case diakhiri break agar case berikutnya tidak ikut terjalankan.

php lupa-break.php
<?php

$tingkat = 2;

// tanpa break, eksekusi jatuh ke case berikutnya
switch ($tingkat) {
    case 1:
        echo 'Dasar', PHP_EOL;
    case 2:
        echo 'Menengah', PHP_EOL;
    case 3:
        echo 'Mahir', PHP_EOL;
        break;
    default:
        echo 'Tidak dikenal', PHP_EOL;
}
text Keluaran
Menengah
Mahir

Keluaran di atas memperlihatkan $tingkat bernilai 2 menjalankan case 2, lalu karena tidak ada break, eksekusi berlanjut ke case 3 dan mencetak Mahir juga. Baru break pada case 3 menghentikan switch, sehingga default tidak tersentuh. Karena tidak ada error yang muncul, kebiasaan menutup setiap case dengan break menjadi pencegahan yang paling andal.

Perulangan for#

Perulangan for mengulang sebuah blok selama kondisinya bernilai true, dengan tiga ekspresi di dalam tanda kurungnya, yaitu inisialisasi variabel kendali, kondisi, dan perubahan variabel kendali. Inisialisasi dieksekusi sekali di awal, kondisi diuji sebelum setiap putaran, dan perubahan dijalankan setelah tubuh blok selesai. Bentuk ini paling tepat bila jumlah putaran sudah dapat dihitung sebelum perulangan dimulai.

php jumlah-deret.php
<?php

$total = 0;

for ($i = 1; $i <= 100; $i++) {
    $total += $i;
}

echo "Jumlah angka 1 sampai 100: $total", PHP_EOL;
text Keluaran
Jumlah angka 1 sampai 100: 5050

Perulangan tersebut menambahkan $i ke $total seratus kali, dan hasilnya 5050 dapat dihitung ulang secara manual. Variabel kendali $i hanya berperan di dalam perulangan ini dan tidak dipakai lagi setelah perulangan selesai. Dua pernyataan mengendalikan jalannya perulangan, yaitu break yang menghentikannya seketika dan continue yang melompat ke putaran berikutnya, sebagaimana contoh berikut.

php break-continue.php
<?php

for ($i = 1; $i <= 10; $i++) {
    if ($i % 2 === 0) {
        continue; // lewati angka genap
    }

    if ($i > 7) {
        break; // berhenti sebelum mencapai 8
    }

    echo "$i ";
}

echo PHP_EOL;
text Keluaran
1 3 5 7

Pernyataan continue membatalkan sisa tubuh blok untuk angka genap, sedangkan break menghentikan perulangan begitu $i bernilai 9. Keluarannya berhenti pada 7 karena 8 dilewati continue dan 9 langsung memenuhi kondisi break. Bila kedua pernyataan itu dihapus, seluruh angka 1 sampai 10 tercetak.

while dan do-while#

Perulangan while hanya memuat kondisi. Kondisi diuji sebelum setiap putaran, dan tubuhnya dijalankan selama kondisi bernilai true. Bila kondisi langsung bernilai false sejak awal, tubuhnya tidak dijalankan sama sekali. Bentuk ini cocok untuk tugas yang jumlah putarannya ditentukan oleh keadaan, bukan oleh penghitung.

php hitung-mundur.php
<?php

$cetak = 3;

while ($cetak > 0) {
    echo "Cetak ke-$cetak", PHP_EOL;
    $cetak--;
}

echo "Selesai", PHP_EOL;
text Keluaran
Cetak ke-3
Cetak ke-2
Cetak ke-1
Selesai

Kondisi $cetak > 0 menghasilkan true tiga kali, dan perulangan berhenti setelah $cetak mencapai 0. Pengurangan $cetak-- di dalam tubuh memastikan kondisi pada akhirnya bernilai false. Kelupaan menuliskan perubahan semacam ini memicu perulangan tak berujung sebagaimana dibahas pada bagian kesalahan umum. Perulangan do-while membalik urutan pengujian tersebut, yaitu tubuh dijalankan lebih dulu dan kondisi diuji sesudahnya, sehingga tubuh pasti dijalankan minimal satu kali.

Baris penutup do-while diakhiri titik koma setelah tanda kurungnya, dan kelupaan tanda ini memicu error sintaks ketika berkas dijalankan. Susunan yang menguji kondisi sesudah tubuh juga menuntut agar variabel yang dirujuk kondisi sudah terdefinisi sebelum blok dimasuki, sebagaimana $saldo pada contoh berikut.

php minimal-sekali.php
<?php

$saldo = 0;

// kondisi awal sudah bernilai false, tetapi tubuh tetap dijalankan sekali
do {
    echo "Tubuh dijalankan, saldo: $saldo", PHP_EOL;
    $saldo += 50;
} while ($saldo > 100);
text Keluaran
Tubuh dijalankan, saldo: 0

Kondisi $saldo > 100 bernilai false sejak awal, tetapi tubuh tetap tercetak satu kali. Urutan pengujian itulah satu-satunya pembeda do-while dari while, sehingga pemilihannya hanya relevan bila putaran pertama wajib terjadi, misalnya untuk menampilkan menu sebelum meminta pilihan.

foreach dan jebakan referensi#

Perulangan foreach didedikasikan untuk array dan mengiterasi nilainya satu per satu tanpa variabel kendali manual. Array adalah struktur data terurut yang menyimpan sekumpulan nilai. Bentuk pertama foreach mengambil nilai saja dengan pola foreach ($array as $nilai), sedangkan bentuk kedua mengambil kunci dan nilai sekaligus dengan pola foreach ($array as $kunci => $nilai). Contoh berikut membaca daftar stok yang memetakan nama bahan ke jumlahnya.

php daftar-stok.php
<?php

$stok = ['kertas' => 40, 'tinta' => 12, 'amplop' => 75];

foreach ($stok as $bahan => $jumlah) {
    echo "$bahan: $jumlah", PHP_EOL;
}
text Keluaran
kertas: 40
tinta: 12
amplop: 75

Mengubah elemen array dari dalam foreach memerlukan referensi, yaitu tanda & sebelum variabel nilainya. Referensi membuat $nilai menunjuk ke elemen aslinya, sehingga penugasan ke $nilai ikut mengubah array tersebut. Setelah perulangan berakhir, $nilai masih menjadi referensi ke elemen terakhir, dan di sinilah jebakannya.

php jebakan-referensi.php
<?php

$suhu = [24.0, 31.5, 22.8];

foreach ($suhu as &$nilai) {
    $nilai += 0.5;
}

// $nilai masih menjadi referensi ke elemen terakhir array
$nilai = 100.0;

echo "Tanpa unset:", PHP_EOL;
print_r($suhu);

unset($nilai);

$suhu = [24.0, 31.5, 22.8];

foreach ($suhu as &$nilai) {
    $nilai += 0.5;
}
unset($nilai);

$nilai = 100.0;

echo "Dengan unset:", PHP_EOL;
print_r($suhu);
text Keluaran
Tanpa unset:
Array
(
    [0] => 24.5
    [1] => 32
    [2] => 100
)
Dengan unset:
Array
(
    [0] => 24.5
    [1] => 32
    [2] => 23.3
)

Bagian pertama keluaran memperlihatkan elemen ketiga berubah menjadi 100, padahal penugasan $nilai = 100.0 dituliskan setelah perulangan selesai. Penyebabnya, $nilai masih menjadi referensi ke elemen terakhir array, sehingga penugasan biasa ikut mengubah array itu. Memanggil unset($nilai) tepat setelah foreach memutus referensinya, dan bagian kedua keluaran membuktikan array tidak tersentuh setelah referensinya diputus.

Kesalahan umum#

Perulangan tak berujung terjadi bila kondisinya tidak pernah bernilai false, misalnya karena variabel kendali lupa diubah atau perubahannya justru menjauh dari batas. Skrip yang mengalaminya tidak pernah selesai dan harus dihentikan paksa, sehingga contoh berikut tidak dijalankan di sandbox.

php Contoh: perulangan tak berujung
// tidak-dijalankan: perulangan ini tidak pernah berhenti
while (true) {
    echo 'berulang tanpa akhir';
}

Kesalahan kedua adalah mengira penugasan pada variabel foreach tanpa referensi ikut mengubah array. Tanpa tanda &, $nilai hanyalah salinan nilai elemen, sehingga perubahan di dalam tubuh hilang begitu putaran berikutnya dimulai. Perubahan elemen array memerlukan referensi &$nilai sebagaimana diperlihatkan pada contoh jebakan-referensi.php, disertai unset setelahnya.

Kesalahan ketiga kembali ke switch, yaitu lupa break yang sudah diperlihatkan pada contoh lupa-break.php. Perlu diingat pula bahwa switch membandingkan secara lemah, sehingga string '1' cocok dengan case bernilai 1. Bila pemetaan membutuhkan kecocokan ketat, gunakan ekspresi match sebagai gantinya.

Perbandingan switch terhadap string juga peka huruf besar dan kecil, sehingga case 'Sabtu' tidak menangkap masukan 'sabtu'. Ubah masukan teks menjadi huruf kecil dengan strtolower() sebelum masuk ke switch, atau daftarkan semua bentuk tulisan yang mungkin pada case yang ditumpuk.

Ringkasan#

  • switch membandingkan secara lemah dan menembus ke case berikutnya bila break tidak dituliskan, sedangkan case bertumpuk memanfaatkan penembusan itu secara disengaja.
  • for mengulang dengan variabel kendali dan cocok untuk jumlah putaran yang sudah pasti, sedangkan while menguji kondisi sebelum tubuh dan do-while mengujinya sesudahnya sehingga tubuh minimal sekali dijalankan.
  • foreach mengiterasi array dalam bentuk nilai saja maupun kunci dan nilai, dan perubahan elemen memerlukan referensi.
  • Referensi &$nilai tetap menempel pada elemen terakhir setelah perulangan selesai, sehingga unset dituliskan bila referensi tidak dipakai lagi.

Referensi#