Setiap properti dan metode kelas memiliki tingkat visibilitas yang menentukan dari mana anggota tersebut boleh diakses. Topik ini membahas tiga kata kunci visibilitas pada PHP, yaitu public, protected, dan private, beserta prinsip enkapsulasi (encapsulation) yang mendasari penggunaannya. Setelah topik ini, batas antara keadaan internal objek dan antarmuka yang boleh dipakai pihak luar dapat ditetapkan secara terencana, bukan sekadar terbentuk mengikuti kebiasaan menulis kode.
Tiga tingkat visibilitas#
Visibilitas ditulis pada deklarasi anggota, sebelum nama properti atau sebelum nama metode. Ketiga tingkatnya dirangkum pada tabel berikut.
| Tingkat | Kelas sendiri | Kelas turunan | Kode di luar kelas |
|---|---|---|---|
public | dapat diakses | dapat diakses | dapat diakses |
protected | dapat diakses | dapat diakses | tidak dapat diakses |
private | dapat diakses | tidak dapat diakses | tidak dapat diakses |
Anggota public membentuk antarmuka kelas, yaitu bagian yang boleh dipakai kode lain tanpa syarat. Anggota private hanya terlihat di dalam kelas yang mendeklarasikannya, sehingga cocok untuk keadaan internal yang nilainya harus dijaga. Anggota protected berada di antara keduanya, yaitu tetap tersembunyi dari luar tetapi dapat dipakai oleh kelas yang mewarisinya. Sejak PHP 7.1, ketiga kata kunci ini juga berlaku untuk konstanta kelas. Properti yang dipromosikan pada constructor wajib membawa salah satu kata kunci ini secara eksplisit. Kata kunci itulah yang membedakan properti hasil promosi dari parameter biasa.
Pembatasan ini ditegakkan oleh PHP pada saat akses dilakukan, bukan sekadar kesepakatan penulisan. Skrip berikut mencoba membaca properti private dan memanggil metode private dari kode di luar kelas, lalu menangkap errornya agar program tetap berjalan dan pesannya dapat diperiksa.
<?php
declare(strict_types=1);
class Buku
{
private string $kode = 'BK-001';
private int $stok = 2;
public function stokTersedia(): int
{
return $this->stok;
}
private function perbaruiKode(string $kode): void
{
$this->kode = $kode;
}
}
$buku = new Buku();
try {
echo $buku->stok;
} catch (Throwable $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}
try {
$buku->perbaruiKode('BK-999');
} catch (Throwable $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}
echo 'Stok tersedia: ', $buku->stokTersedia(), "\n";Error: Cannot access private property Buku::$stok
Error: Call to private method Buku::perbaruiKode() from global scope
Stok tersedia: 2Kedua baris error pada keluaran menunjukkan bahwa akses dari luar kelas dihentikan sebelum properti atau metode dijalankan. Baris terakhir membuktikan bahwa anggota private tetap dapat digunakan dari dalam kelasnya, yaitu metode stokTersedia() membaca $this->stok tanpa hambatan.
Menyembunyikan keadaan internal#
Visibilitas berguna ketika digunakan untuk enkapsulasi, yaitu menyembunyikan keadaan internal objek dan hanya membuka operasi yang bermakna. Anggota public pada contoh sebelumnya dibiarkan tanpa penjagaan, sehingga kode luar dapat menuliskan $buku->stok = -5; dan membuat keadaan yang tidak masuk akal. Dengan membuat $stok bersifat private, satu-satunya cara mengubah stok adalah melalui metode yang menetapkan aturannya, misalnya peminjaman hanya boleh terjadi bila stok masih ada.
Skrip berikut menerapkan pola tersebut. Constructor menggunakan constructor property promotion dengan visibilitas private, sehingga properti $stok langsung tersembunyi sejak objek dibuat. Metode pinjamkan() menetapkan bahwa peminjaman gagal bila stok kosong, sedangkan penurunan stok hanya terjadi setelah aturan tersebut terpenuhi.
<?php
declare(strict_types=1);
class Buku
{
public function __construct(
private string $kode,
private int $stok = 2,
) {
}
public function pinjamkan(): bool
{
if ($this->stok < 1) {
return false;
}
$this->stok--;
return true;
}
public function kembalikan(): void
{
$this->stok++;
}
public function stok(): int
{
return $this->stok;
}
}
$buku = new Buku('BK-001');
if ($buku->pinjamkan()) {
echo 'pinjam pertama berhasil', "\n";
}
if ($buku->pinjamkan()) {
echo 'pinjam kedua berhasil', "\n";
}
if ($buku->pinjamkan()) {
echo 'pinjam ketiga berhasil', "\n";
} else {
echo 'pinjam ketiga gagal karena stok kosong', "\n";
}
$buku->kembalikan();
echo 'Stok sekarang: ', $buku->stok(), "\n";pinjam pertama berhasil
pinjam kedua berhasil
pinjam ketiga gagal karena stok kosong
Stok sekarang: 1Keluaran memperlihatkan aturan itu bekerja. Dua salinan yang tersedia cukup untuk dua peminjaman, peminjaman ketiga ditolak oleh metode itu sendiri, dan satu pengembalian menaikkan stok menjadi satu. Kode pemanggil tidak perlu tahu cara stok disimpan karena yang diperlukan hanyalah pertanyaan yang bermakna, yaitu apakah peminjaman berhasil.
protected untuk kelas turunan#
Anggota protected menyatukan dua kebutuhan yang sering muncul bersamaan, yaitu menyembunyikan keadaan dari kode luar sekaligus memperbolehkan kelas turunannya memakainya. Kelas turunan dibuat dengan kata kunci extends, dan penjelasan lengkap mekanisme pewarisannya dibahas pada topik pewarisan. Untuk visibilitas, hal yang penting di sini adalah kelas turunan diperlakukan sebagai bagian dari kelas induk, sehingga $this di dalam kelas turunan masih dapat mengakses anggota protected milik induknya.
Skrip berikut mendeklarasikan kelas Pengguna dengan properti protected bernama $nama, lalu kelas Anggota yang mewarisinya dan membaca $this->nama dari metodenya sendiri. Akses dari luar tetap ditolak, dan errornya ditangkap untuk memperlihatkan pesannya.
<?php
declare(strict_types=1);
class Pengguna
{
public function __construct(protected string $nama)
{
}
public function sapa(): string
{
return "Halo, {$this->nama}.";
}
}
class Anggota extends Pengguna
{
public function kartuPerpustakaan(): string
{
return "Kartu atas nama {$this->nama}, berlaku satu tahun.";
}
}
$anggota = new Anggota('Dewi');
echo $anggota->sapa(), "\n";
echo $anggota->kartuPerpustakaan(), "\n";
try {
echo $anggota->nama;
} catch (Throwable $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}Halo, Dewi.
Kartu atas nama Dewi, berlaku satu tahun.
Error: Cannot access protected property Anggota::$namaDua metode dari dua kelas yang berbeda berhasil membaca $this->nama, sedangkan pembacaan dari luar menghasilkan error. Pesan errornya menyebut Anggota::$nama karena PHP menilai akses dari sudut pandang objek yang sedang dipakai. Aksesnya tetap ditolak karena kode yang melakukan akses berada di luar kedua kelas tersebut.
Kesalahan umum#
- Membuat semua properti
publicdemi kepraktisan. Keadaan internal yang terbuka penuh membuat aturan seperti batas stok tidak dapat ditegakkan, karena penulisan langsung dari luar melewati metode penjaganya. Jadikan propertiprivatedan sediakan metode yang menerapkan aturannya. - Menyediakan getter dan setter untuk seluruh properti secara otomatis. Visibilitas
privateyang segera diikuti sepasang metode pembaca dan penulis tanpa validasi hanya memindahkan masalah ke tempat lain tanpa penjagaan yang nyata. Sediakan metode akses hanya untuk data yang memang perlu dibaca atau diubah, dan berikan pemeriksaan pada jalur yang mengubah keadaan. - Mengakses properti
privateinduk dari kelas turunan. Pesan errornya menyebutCannot access private property, padahal penulisnya yakin berada di dalam kelas yang berhak. Hal ini terjadi karenaprivatemenutup akses termasuk dari turunannya. Pilihprotecteduntuk anggota yang memang disiapkan untuk kelas turunan. - Memperlakukan
protectedsebagaipublickedua. Anggotaprotectedtetap tersembunyi dari kode luar, sehingga keputusan menjadikannyaprotectedberarti komitmen bahwa bentuk keadaan tersebut akan dipertahankan bagi kelas turunannya. Ubah anggotaprotecteddengan kehati-hatian yang sama seperti anggotapublic, karena kelas turunannya bergantung padanya.
Ringkasan#
public,protected, danprivatemenetapkan siapa yang boleh mengakses sebuah anggota, yaitu semuanya, kelas beserta turunannya, atau kelas yang mendeklarasikannya saja.- PHP menegakkan visibilitas pada saat akses, dan akses yang melanggar memicu
Erroryang pesannya menyebut properti atau metode yang bersangkutan. - Enkapsulasi menyembunyikan keadaan internal sehingga perubahan hanya dapat terjadi melalui metode yang menerapkan aturan, seperti penjagaan stok pada
pinjamkan(). protectedmenyediakan jalan tengah untuk kelas turunan, sedangkan anggotaprivatesepenuhnya milik kelas yang mendeklarasikannya.
Referensi#
- Visibility — Manual PHP
— Menetapkan makna
public,protected, danprivatebeserta aturan aksesnya. - Constructors and Destructors — Manual PHP — Menjelaskan visibilitas pada properti yang dipromosikan di constructor.
- Class Constants — Manual PHP — Menyebut visibilitas konstanta kelas yang didukung sejak PHP 7.1.