Data dari MySQL belum berguna sebelum tampil di halaman HTML. PHP menyediakan beberapa cara untuk memindahkan hasil query ke markup, dan pilihanmu menentukan seberapa rapi kode saat tabel bertambah besar. Tujuh pendekatan berikut dibandingkan dari sisi kenyamanan, keamanan, dan biaya perawatan.

1. mysqli_fetch_array dengan while loop

Cara paling dasar: jalankan query, lalu iterasi hasilnya dengan while. Setiap baris dikembalikan sebagai array asosiatif maupun numerik, tergantung parameter yang kamu pakai.

$hasil = mysqli_query($koneksi, "SELECT nama, email FROM pengguna");
echo "<table>";
while ($baris = mysqli_fetch_array($hasil, MYSQLI_ASSOC)) {
    echo "<tr><td>" . htmlspecialchars($baris['nama']) . "</td>"
       . "<td>" . htmlspecialchars($baris['email']) . "</td></tr>";
}
echo "</table>";

Kelebihannya: tidak ada lapisan tambahan, mudah dibaca pemula. Kelemahannya: HTML bercampur dengan logika PHP, dan htmlspecialchars gampang terlupa di satu tempat. Kalau kamu memakai pendekatan ini, pastikan koneksi dibuat dengan cara yang benar seperti di panduan menghubungkan PHP ke MySQL.

2. mysqli_fetch_assoc plus heredoc

Alih-alih menempel string dengan titik, kamu bisa menulis potongan HTML utuh di dalam heredoc lalu menyisipkan variabel. Hasilnya lebih mudah dibaca saat baris tabel punya banyak kolom.

while ($baris = mysqli_fetch_assoc($hasil)) {
    $nama = htmlspecialchars($baris['nama']);
    $email = htmlspecialchars($baris['email']);
    echo <<<HTML
    <tr>
        <td>{$nama}</td>
        <td>{$email}</td>
    </tr>
    HTML;
}

Perhatikan bahwa kita membersihkan data sebelum masuk heredoc. Ini titik yang sering terlewat: escaping harus terjadi di setiap variabel, bukan sekali di akhir.

3. PDO dengan fetchAll dan template terpisah

PDO memisahkan pengambilan data dan penyajian dengan lebih tegas. Kamu kumpulkan dulu semua baris ke array, lalu render di file view.

$stmt = $pdo->query("SELECT nama, email FROM pengguna");
$pengguna = $stmt->fetchAll(PDO::FETCH_ASSOC);
include 'views/daftar-pengguna.php';

Di dalam view, foreach mengulang array dengan htmlspecialchars pada setiap keluaran. Pola ini membuat file logika dan file tampilan bisa diubah tanpa saling mengganggu.

4. Pola View Partial per Baris

Kalau satu baris tabel cukup rumit (punya badge status, tautan aksi, tanggal terformat), pindahkan ke file kecil sendiri. Setiap iterasi cukup melakukan include file baris.

  • views/pengguna/baris.php berisi markup satu <tr>.
  • Variabel $baris tersedia sebelum include.
  • Perubahan desain baris tidak menyentuh file daftar utama.

Konsekuensinya, kamu harus disiplin soal nama variabel karena semua file berbagi scope yang sama. Beri prefix jelas seperti $baris supaya tidak bentrok dengan variabel lain di halaman.

5. Output buffering dengan ob_start

Alih-alih echo berkali-kali, kamu bisa menangkap seluruh hasil render ke string lewat output buffering, lalu mengirimkannya sekaligus.

ob_start();
foreach ($pengguna as $baris) {
    include 'views/pengguna/baris.php';
}
$html = ob_get_clean();
echo $html;

Teknik ini berguna ketika hasil HTML perlu diproses lagi, misalnya dikirim sebagai respons AJAX atau disimpan ke cache file. Untuk halaman biasa, manfaatnya kecil dan menambah satu lapisan yang harus dipahami.

6. Template engine seperti Twig atau Blade

Template engine menambahkan sintaks khusus untuk perulangan dan escaping otomatis. Di Twig, satu baris tabel cukup ditulis seperti ini:

{% for pengguna in daftar %}
    <tr>
        <td>{{ pengguna.nama }}</td>
        <td>{{ pengguna.email }}</td>
    </tr>
{% endfor %}

Escaping jadi bawaan, jadi kamu tidak perlu menulis htmlspecialchars di setiap variabel. Harga yang dibayar adalah dependensi tambahan lewat Composer dan kurva belajar sintaks baru. Untuk proyek kecil yang hanya punya dua halaman, ini berlebihan.

7. Menggabungkan PHP dengan JavaScript untuk tabel dinamis

Beberapa kasus lebih enak diselesaikan dengan mengirim data JSON dari PHP lalu merender tabel di sisi klien. Kamu bisa memakai jQuery untuk memanipulasi baris setelah data tiba. Contoh pemilihan elemen dan penelusuran DOM bisa dilihat di cara memilih elemen dengan selector jQuery.

Pendekatan ini masuk akal kalau tabel perlu pengurutan, pencarian, atau pemuatan ulang sebagian. Kalau hanya menampilkan data statis, menambah JavaScript malah memperbesar permukaan bug, termasuk masalah escaping di sisi klien yang berbeda dari di PHP.

Perbandingan singkat

Cara Cocok untuk Catatan
mysqli_fetch_array Skrip satu file Rentan lupa escaping
Heredoc Tabel dengan banyak kolom Markup lebih rapi
PDO + view Proyek menengah Logika dan tampilan terpisah
Baris partial Baris dengan markup kompleks Perlu disiplin nama variabel
Output buffering Respons AJAX, cache Lapisan tambahan
Twig/Blade Proyek besar, tim Butuh Composer
PHP + JavaScript Tabel interaktif Escaping ganda

Memilih berdasarkan ukuran proyek

Untuk skrip sekali pakai, cara nomor 1 atau 2 sudah cukup. Begitu ada lebih dari tiga halaman yang menampilkan data serupa, pisahkan view seperti pada cara 3. Template engine baru masuk hitungan ketika tim berisi lebih dari dua orang dan kamu butuh aturan escaping yang seragam.

Hal yang sama berlaku saat menampilkan daftar panjang. Kalau hasil query mencapai ratusan baris, tampilkan bertahap dan pindahkan logika pemotongan ke helper terpisah, seperti dijelaskan pada panduan membuat pagination PHP tanpa library tambahan. Dengan begitu query dan render tetap sederhana meski jumlah data bertambah.

Kesalahan yang sering terjadi

  • Menjalankan query di dalam while. Ambil data sekali, lalu render.
  • Melupakan htmlspecialchars pada kolom yang bisa diisi pengguna.
  • Mencetak $baris dengan print_r dan lupa menghapusnya.
  • Memakai mysqli_fetch_array tanpa MYSQLI_ASSOC, lalu bingung dengan indeks angka.

Validasi masukan tetap wajib meski kamu hanya menampilkan data. Perbandingan antara validasi form di PHP dan JavaScript membantu menentukan lapisan mana yang menangani pemeriksaan.

Ringkasan

Tidak ada satu cara terbaik untuk semua proyek. Skrip pendek cukup dengan fetch array, proyek menengah lebih nyaman memakai PDO dan view terpisah, sedangkan tim besar mendapat manfaat dari template engine. Yang tidak boleh dikompromikan adalah escaping keluaran dan pemisahan query dari markup.

Pertanyaan yang Sering Diajukan

Apakah boleh memakai mysqli dan PDO dalam satu proyek?

Secara teknis bisa, tapi menyulitkan perawatan karena dua gaya penanganan error dan pengambilan data berbeda. Pilih satu sejak awal, biasanya PDO kalau proyek kemungkinan berganti jenis database.

Kenapa data saya tampil sebagai &quot;Resource id #5&quot;?

Itu terjadi ketika kamu mencetak objek hasil query langsung, bukan barisnya. Panggil fungsi fetch seperti mysqli_fetch_assoc atau fetch pada statement PDO untuk mendapatkan array baris.

Apakah template engine memperlambat halaman?

Template engine punya biaya kompilasi di awal, tapi hasil kompilasinya biasanya di-cache sehingga permintaan berikutnya cepat. Untuk halaman dengan lalu lintas rendah, selisihnya jarang terasa dibandingkan waktu query database.