Lingkup

Lingkup variabel fungsi, variabel static, dan jebakan keyword global.

Daftar isi

Setiap fungsi PHP memiliki lingkup variabelnya sendiri, yaitu wilayah tempat sebuah nama variabel berlaku. Topik ini membahas lingkup lokal pada tubuh fungsi, variabel static yang nilainya bertahan antar pemanggilan, serta kata kunci global beserta jebakannya. Setelah topik ini dibaca, batas hidup sebuah variabel dapat dipastikan, dan aliran data antara fungsi dengan lingkup luar dapat diatur secara eksplisit.

Lingkup lokal fungsi#

Variabel yang dideklarasikan di dalam tubuh fungsi bersifat lokal, yaitu diciptakan saat fungsi dipanggil dan hilang saat fungsinya selesai. Variabel di luar fungsi juga tidak terlihat dari dalam fungsi, sehingga dua nama yang sama pada dua lingkup berbeda merujuk dua penyimpanan yang terpisah. Parameter berperilaku sama, karena parameter pada dasarnya adalah variabel lokal yang nilainya diisi dari argumen pemanggilan.

Aturan ini membuat fungsi menjadi unit yang mandiri. Hasil pemanggilan tidak bergantung pada variabel apa pun di luar deklarasinya, dan pemanggilan yang berulang selalu dimulai dari keadaan yang bersih. Kode yang bergantung pada perilaku ini lebih mudah diuji karena masukannya eksplisit lewat parameter dan keluarannya eksplisit lewat nilai kembalian.

Skrip berikut membandingkan dua lingkup yang memuat nama $total yang sama. Di dalam fungsi, $total adalah variabel lokal baru yang selalu dimulai dari nol, sedangkan $total di luar tetap bernilai 100 setelah dua pemanggilan.

php lingkup-lokal.php
<?php
declare(strict_types=1);

$total = 100;

function tambahPoin(int $poin): int
{
    $total = 0;            // variabel lokal baru, terpisah dari $total di luar
    $total += $poin;
    return $total;
}

echo tambahPoin(25), "\n";
echo tambahPoin(30), "\n";
echo $total, "\n";
text Keluaran
25
30
100

Nilai 100 pada baris keluaran terakhir membuktikan bahwa dua variabel bernama $total tersebut benar-benar terpisah dan tidak saling memengaruhi. Apabila fungsi memang dimaksudkan mengubah $total milik lingkup luar, hasil perhitungannya dikembalikan dengan return lalu disimpan ke variabel di titik pemanggilan, sehingga perubahan nilai terlihat.

Variabel static#

Variabel lokal yang diawali kata kunci static mempertahankan nilainya antar pemanggilan. Inisialisasinya dijalankan sekali, yaitu pada pemanggilan pertama, sedangkan pemanggilan berikutnya melanjutkan dari nilai terakhir yang tersimpan. Variabel semacam ini tetap tersembunyi dari luar karena lingkupnya tetap lokal, sehingga keadaan yang disimpan hanya dapat dilihat oleh fungsi itu sendiri.

Penggunaan yang lazim adalah penghitung panggilan, cache hasil perhitungan sederhana, dan penanda proses yang hanya boleh berjalan sekali. Setiap fungsi memiliki variabel static-nya sendiri, sehingga dua fungsi yang menggunakan nama variabel yang sama tidak saling bertukar nilai.

Skrip berikut memuat dua fungsi penghitung dengan variabel static bernama sama. Angka pada fungsi pertama berlanjut dari satu ke tiga, sedangkan fungsi kedua memulai dari seratus dan melanjutkannya secara terpisah.

php penghitung-static.php
<?php
declare(strict_types=1);

function berikutnya(): int
{
    static $nomor = 0;
    $nomor++;
    return $nomor;
}

function berikutnyaKedua(): int
{
    static $nomor = 100;
    $nomor++;
    return $nomor;
}

echo berikutnya(), "\n";
echo berikutnya(), "\n";
echo berikutnya(), "\n";
echo berikutnyaKedua(), "\n";
text Keluaran
1
2
3
101

Angka 101 pada baris terakhir menunjukkan bahwa $nomor milik berikutnyaKedua() tidak terpengaruh oleh tiga pemanggilan berikutnya(), karena setiap fungsi menyimpan variabel static-nya secara terpisah. Inisialisasinya ditulis sebagai ekspresi konstan, misalnya angka atau string literal, dan baris itu baru dieksekusi pada pemanggilan pertama.

Kata kunci global dan jebakannya#

Kata kunci global menghubungkan fungsi dengan variabel lingkup luar tanpa menyalin nilainya. Pernyataan global $stok; membuat nama $stok di dalam fungsi merujuk pada variabel global yang sama, sehingga pengubahan di dalam fungsi langsung terlihat di luar. Perilaku ini menjadikan global pemicu masalah, bukan sekadar fitur yang jarang digunakan.

Masalah utamanya adalah ketergantungan tersembunyi. Tanda tangan fungsi yang menggunakan global tidak menyebutkan data mana yang dibaca dan diubah, sehingga pembaca harus menelusuri tubuh fungsi untuk mengetahuinya. Pengujian pun menjadi lebih sulit karena variabel global harus disiapkan terlebih dahulu. Satu fungsi yang mengubah variabel global juga mengikat seluruh program pada nama variabel tersebut, karena penggantian nama berarti mengubah perilaku fungsi yang letaknya jauh dari titik pemanggilan.

Alternatifnya adalah melewatkan data melalui parameter dan mengembalikan hasilnya melalui nilai kembalian, sehingga aliran data terbaca dari tanda tangan fungsi. Skrip berikut menggunakan kedua cara pada satu program agar perbedaannya terlihat pada keluaran yang sama.

php jebakan-global.php
<?php
declare(strict_types=1);

$stok = 40;

function pinjam(int $jumlah): void
{
    global $stok;
    $stok -= $jumlah;
}

function pinjamDenganParameter(int $stok, int $jumlah): int
{
    return $stok - $jumlah;
}

pinjam(5);
echo 'Lewat global: ', $stok, "\n";

$stok = pinjamDenganParameter($stok, 3);
echo 'Lewat parameter: ', $stok, "\n";
text Keluaran
Lewat global: 35
Lewat parameter: 32

Kesalahan umum#

  • Mengharapkan variabel luar terlihat di dalam fungsi. PHP tidak menghubungkan dua lingkup secara otomatis, sehingga membaca variabel luar tanpa global menghasilkan variabel lokal bernilai null dan memicu peringatan. Pesan peringatannya menyebut nama variabel yang tidak terdefinisi, sehingga penyebabnya cepat ditemukan. Perbaikannya dengan meneruskan nilai lewat parameter.
  • Menganggap inisialisasi static dijalankan setiap pemanggilan. Baris static $nomor = 0; hanya dieksekusi sekali pada pemanggilan pertama, sehingga penghitungnya tidak kembali ke nilai awal pada pemanggilan berikutnya. Gunakan parameter atau kondisi eksplisit apabila pengaturan ulang memang dikehendaki.
  • Menyembunyikan perubahan penting di balik global. Fungsi yang mengubah keadaan global menimbulkan efek samping yang tidak terlihat dari titik panggil. Deklarasikan perubahan tersebut pada tanda tangan fungsi, misalnya menerima keadaan saat ini dan mengembalikan keadaan barunya.
  • Membaca variabel superglobal langsung di dalam fungsi. Variabel $_GET dan $_POST memang terlihat dari dalam fungsi, tetapi fungsi yang membacanya secara langsung menjadi sulit diuji dan bergantung pada bentuk permintaan HTTP. Ambil nilainya di titik masuk, lalu teruskan ke fungsi sebagai parameter biasa.

Ringkasan#

  • Variabel di dalam fungsi bersifat lokal dan terpisah dari variabel bernama sama di luar, sehingga setiap pemanggilan dimulai dari keadaan bersih.
  • Variabel lokal static dipertahankan antar pemanggilan, diinisialisasi sekali, dan tetap tersembunyi dari lingkup luar.
  • global menghubungkan nama lokal dengan variabel global yang sama sehingga perubahan langsung terlihat di luar, tetapi menyembunyikan ketergantungan dari tanda tangan fungsi.
  • Jalur data yang bersih adalah parameter untuk masukan dan nilai kembalian untuk keluaran, sedangkan superglobal merupakan pengecualian yang terlihat dari lingkup mana pun.

Referensi#