Sejauh ini setiap penugasan membuat salinan: $b = $a menyalin isi $a ke wadah baru bernama $b, dan mengubah salah satunya tidak menyentuh yang lain. Kadang-kadang kita justru menginginkan dua nama untuk satu nilai — agar perubahan lewat nama yang satu terlihat dari nama lainnya. PHP menyediakan mekanisme variable references untuk kebutuhan itu, dan seperti halnya pisau tajam, ia sangat berguna bila dipahami dan berbahaya bila disalahpahami. Chapter ini membedah apa sebenarnya references itu, kapan ia berguna, dan jebakan klasik yang menyertainya.
Reference Adalah Alias, Bukan Salinan #
Operator & yang ditempelkan pada variabel menciptakan reference — ikatan yang membuat dua nama menunjuk ke wadah nilai yang sama. Mari kita lihat perbedaannya dengan salinan biasa secara berdampingan:
<?php
$namaAsli = "Budi";
$namaSalinan = $namaAsli;
$namaAlias = &$namaAsli;
$namaAlias = "Siti";
echo "Asli: $namaAsli\n";
echo "Alias: $namaAlias\n";
var_dump($namaSalinan);
$namaAsli = "Rina";
echo "Setelah asli diubah -> Alias: $namaAlias\n";Output yang Dihasilkan:
Asli: Siti
Alias: Siti
string(4) "Budi"
Setelah asli diubah -> Alias: RinaMari kita telaah kode di atas:
- Baris 3 (
$namaSalinan = $namaAsli;): penugasan biasa — nilai"Budi"disalin ke wadah baru, sehingga$namaSalinanberdiri sendiri. - Baris 4 (
$namaAlias = &$namaAsli;): tanda&membuat$namaAliasmenjadi nama kedua untuk wadah milik$namaAsli. Tidak ada penyalinan nilai. - Baris 6 (
$namaAlias = "Siti";): karena kedua nama menunjuk wadah yang sama, penulisan lewat$namaAliasjuga mengubah apa yang dibaca$namaAsli— keduanya kini bernilai"Siti", sementara$namaSalinantetap"Budi". - Baris 11-12: arah sebaliknya berlaku sama — mengubah lewat
$namaAslijuga terlihat dari$namaAlias.
Apa yang Sebenarnya Terjadi #
Di balik layar, PHP menjaga sebuah symbol table — kamus yang memetakan nama variabel ke wadah nilai. Penugasan biasa membuat entri baru dengan salinan nilai, sedangkan $alias = &$asli membuat dua entri yang menunjuk ke entri wadah yang sama. Inilah definisi tepatnya: reference adalah alias pada symbol table, bukan struktur data terpisah.
Definisi ini juga menjelaskan apa yang reference bukan. Reference bukan pointer seperti di bahasa C: Anda tidak bisa melakukan aritmetika alamat ($alias + 1 tetap diartikan sebagai operasi nilai string, bukan geser alamat), dan tidak ada operator khusus untuk “melihat alamat” sebuah reference. Reference juga tidak mengikat dua variabel secara permanen — nama lain boleh lepas nanti tanpa memengaruhi nama yang tersisa, seperti akan kita buktikan dengan unset() beberapa bagian di bawah.
Reference pada Parameter Fungsi #
Kegunaan paling klasik references adalah membiarkan fungsi mengubah variabel milik pemanggilnya. Cukup tambahkan & sebelum nama parameter:
<?php
$totalBelanja = 100000.0;
function tambahPajak(float &$total, float $persen): void {
$total += $total * $persen;
}
tambahPajak($totalBelanja, 0.11);
echo "Total belanja: ", $totalBelanja, "\n";Output yang Dihasilkan:
Total belanja: 111000Parameter $total kini menjadi alias dari $totalBelanja milik pemanggil, sehingga $total += ... di dalam fungsi langsung mengubah variabel di luar. Bandingkan dengan $persen yang merupakan salinan biasa. Pola ini dipakai fungsi bawaan PHP juga — misalnya sort($array) mengurutkan array asli lewat parameter by reference, bukan mengembalikan array baru.
Perlu dicatat bahwa di PHP modern pola ini semakin jarang dibutuhkan, karena alternatifnya lebih jelas: fungsi menerima nilai, mengembalikan hasil, dan pemanggil yang menugaskan kembali ($total = hitungPajak($total, 0.11);). Function yang mengubah masukannya secara tersembunyi membuat alur data sulit dilacak — simpan pola reference untuk kasus yang benar-benar memintanya, seperti fungsi bawaan sort() atau API yang secara eksplisit mendesainnya.
Mengembalikan Reference dari Fungsi #
Sisi lainnya adalah fungsi yang mengembalikan reference, ditandai & sebelum nama fungsi dan & pada penugasan pemanggilnya. Pola ini berguna untuk memberi akses tulis ke sebagian struktur data yang disimpan di dalam fungsi:
<?php
function &ambilKeranjang(): array {
static $keranjang = [];
return $keranjang;
}
$isi = &ambilKeranjang();
$isi[] = "kopi";
$isi[] = "gula";
var_dump(ambilKeranjang());Output yang Dihasilkan:
array(2) {
[0]=>
string(4) "kopi"
[1]=>
string(4) "gula"
}Fungsi ambilKeranjang() menyimpan array statis (bingkas dari Chapter Variable Scope
: nilainya bertahan antar-pemanggilan) lalu mengembalikan reference-nya. Tanda & pada baris $isi = &ambilKeranjang(); membuat $isi menjadi alias keranjang tersebut, sehingga $isi[] = "kopi" menambah elemen ke array yang sama. Terbukti dari keluaran: var_dump(ambilKeranjang()) — yang memanggil fungsi lagi tanpa & — melihat dua item yang barusan kita tambahkan. Tanpa & di kedua sisi, $isi hanya akan menerima salinan dan keranjang asli tetap kosong.
unset Hanya Memutus Alias #
Karena reference hanyalah nama tambahan, unset() pada satu nama tidak menghapus nilainya selama nama lain masih menunjuk ke sana:
<?php
$a = "nilai penting";
$b = &$a;
unset($b);
var_dump(isset($b));
var_dump($a);Output yang Dihasilkan:
bool(false)
string(13) "nilai penting"Setelah unset($b), nama $b lenyap dari symbol table (isset($b) bernilai false), tetapi wadah nilainya masih dipegang $a sehingga "nilai penting" tetap terbaca. unset() memutus alias, bukan menghancurkan nilai — nilai baru benar-benar dibebaskan saat nama terakhir yang menunjuknya hilang. Perilaku ini membuat references aman dipakai: melepas satu nama tidak pernah merusak data bagi nama lainnya.
Jebakan foreach by Reference #
Sumber bug paling terkenal dunia references ada pada foreach dengan &$nilai — cara idiomatis mengubah setiap elemen array langsung. Mari kita lihat jebakannya selangkah demi selangkah:
<?php
$nilai = [70, 80, 90];
foreach ($nilai as &$n) {
$n += 5;
}
var_dump($nilai);
$n = 100;
var_dump($nilai);Output yang Dihasilkan:
array(3) {
[0]=>
int(75)
[1]=>
int(85)
[2]=>
&int(95)
}
array(3) {
[0]=>
int(75)
[1]=>
int(85)
[2]=>
&int(100)
}Perhatikan keluaran pertama: ketiga elemen naik menjadi 75, 85, 95 — dan var_dump menandai elemen terakhir dengan &int(95) sebagai bukti bahwa $n masih menjadi alias elemen tersebut setelah loop selesai. Karena itu penugasan $n = 100 pada baris berikutnya secara diam-diam menimpa elemen terakhir array menjadi 100. Dalam program nyata, jarak antara loop dan penugasan yang tak sengaja memakai nama $n bisa berpuluhan baris, menjadikan bug ini sangat sulit dilacak.
Perbaikannya satu baris: putus alias tersebut begitu loop selesai:
<?php
$nilai = [70, 80, 90];
foreach ($nilai as &$n) {
$n += 5;
}
unset($n);
$n = 100;
var_dump($nilai);Output yang Dihasilkan:
array(3) {
[0]=>
int(75)
[1]=>
int(85)
[2]=>
int(95)
}Dengan unset($n) tepat setelah loop, nama $n lepas dari array sehingga $n = 100 hanya membuat variabel biasa yang baru — keluaran memperlihatkan array tetap utuh 75, 85, 95.
Ringkasan #
References menjadikan dua nama sebagai alias untuk satu wadah nilai: penugasan lewat nama mana pun terlihat dari nama lainnya, parameter &$x membiarkan fungsi mengubah variabel pemanggil, dan & pada fungsi mengembalikan akses tulis ke data internal. unset() hanya memutus alias tanpa menghancurkan nilai, sementara foreach by reference wajib ditutup dengan unset() untuk mencegah elemen terakhir tertimpa. Ada satu trik sintaks lain yang membuat nama variabel itu sendiri bisa “dihitung” saat runtime — dynamic variables — yang menjadi tema chapter berikutnya.
Referensi #
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
contoh.php
Unduh berkas<?php
// contoh.php — rangkuman Chapter Memahami Variable References.
// Jalankan dengan: php contoh.php
// Alias vs salinan.
$namaAsli = "Budi";
$namaSalinan = $namaAsli;
$namaAlias = &$namaAsli;
$namaAlias = "Siti";
echo "Asli: $namaAsli, Alias: $namaAlias, Salinan: $namaSalinan\n";
// unset hanya memutus alias, tidak menghapus nilainya.
$a = "nilai penting";
$b = &$a;
unset($b);
var_dump(isset($b), $a);
// Reference sebagai parameter fungsi.
function tambahPajak(float &$total, float $persen): void {
$total += $total * $persen;
}
$totalBelanja = 100000.0;
tambahPajak($totalBelanja, 0.11);
echo "Total belanja: ", $totalBelanja, "\n";
// foreach by reference: selalu unset variabel loop setelah selesai.
$nilai = [70, 80, 90];
foreach ($nilai as &$n) {
$n += 5;
}
unset($n);
var_dump($nilai);