Anggota Static

Properti dan metode static, konstanta kelas, serta late static binding.

Daftar isi

Anggota static adalah properti, metode, dan konstanta yang melekat pada kelasnya, bukan pada masing-masing objek yang dibuat darinya. Topik ini membahas cara mendeklarasikan dan mengakses anggota static, konstanta kelas untuk nilai bersama yang tetap, serta late static binding yang mengatur kelas mana yang dimaksud oleh static:: pada saat program berjalan. Contohnya tetap memakai domain perpustakaan, yaitu penomoran kartu anggota, batas peminjaman, dan pelabelan katalog.

Properti dan metode static#

Properti static dideklarasikan dengan kata kunci static setelah kata kunci visibilitasnya. Aksesnya dilakukan melalui nama kelas dengan operator titik dua ganda ::, misalnya Anggota::$jumlah. Hanya ada satu salinan untuk seluruh program, sehingga nilainya dibagi oleh semua objek yang dibuat dari kelas tersebut. Metode static diperlakukan sama, yaitu dipanggil sebagai Kelas::metode() tanpa perlu membuat objek terlebih dahulu.

Metode static tidak dapat menggunakan $this karena tidak ada objek yang sedang menjalankannya. Metode static tetap dapat membaca dan mengubah properti static melalui self::, yaitu penunjuk ke kelas tempat kode itu ditulis. Pola yang cocok untuk anggota static antara lain penghitung bersama, kode berurutan, dan utilitas yang tidak memerlukan keadaan objek.

Skrip berikut memakai satu properti static sebagai penghitung jumlah anggota yang pernah dibuat. Constructor menaikkan penghitung tersebut dan menyusun nomor kartu anggota dari nilai terbarunya, sehingga setiap objek baru memperoleh kode yang berurutan.

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

class Anggota
{
    public string $nama;
    public string $kode;

    public static int $jumlah = 0;

    public function __construct(string $nama)
    {
        self::$jumlah++;
        $this->nama = $nama;
        $this->kode = sprintf('AGT-%03d', self::$jumlah);
    }

    public static function total(): int
    {
        return self::$jumlah;
    }
}

echo Anggota::total(), "\n";

$ali = new Anggota('Ali');
$budi = new Anggota('Budi');

echo $ali->kode, "\n";
echo $budi->kode, "\n";
echo Anggota::total(), "\n";
text Keluaran
0
AGT-001
AGT-002
2

Keluaran memperlihatkan perilaku yang melekat pada kelas. Baris pertama bernilai 0 karena pemanggilan dilakukan sebelum ada objek, dua baris berikutnya membuktikan penghitung itu terus bertambah lintas objek, dan baris terakhir mengembalikan nilai yang sama dari metode static total(). Properti $nama dan $kode tetap milik masing-masing objek, sehingga kelas ini memadukan keadaan per objek dan keadaan bersama dalam satu tempat.

Konstanta kelas#

Konstanta kelas menyimpan nilai yang tetap dan melekat pada kelas, ditulis dengan kata kunci const di dalam tubuh kelas. Aksesnya memakai :: seperti anggota static, dan nilainya wajib berupa ekspresi konstan, misalnya angka, string, array literal, atau ekspresi yang hanya melibatkan nilai konstan. Konstanta kelas dapat diberi visibilitas sejak PHP 7.1, sehingga konstanta yang hanya dipakai internal dapat dibuat private.

Konstanta kelas menggantikan angka dan teks ajaib (magic number dan magic string) yang tersebar di banyak tempat. Ketika nilai berubah, perubahan cukup dilakukan satu kali pada satu tempat, dan seluruh kode yang memakainya otomatis mengikuti. Di dalam metode, konstanta milik kelas sendiri diakses melalui self::NAMA, sedangkan konstanta milik kelas lain ditulis dengan nama kelasnya, misalnya Aturan::BATAS.

Skrip berikut mendefinisikan batas peminjaman sebagai konstanta kelas, memakainya di dalam metode untuk menolak peminjaman yang melebihi batas, lalu menampilkan nilainya dari luar kelas.

php konstanta-kelas.php
<?php
declare(strict_types=1);

class Anggota
{
    public const BATAS_PINJAM = 3;
    public const STATUS_AKTIF = 'aktif';

    private int $jumlahPinjaman = 0;

    public function pinjam(): bool
    {
        if ($this->jumlahPinjaman >= self::BATAS_PINJAM) {
            return false;
        }
        $this->jumlahPinjaman++;
        return true;
    }
}

echo 'Batas pinjam: ', Anggota::BATAS_PINJAM, "\n";

$anggota = new Anggota();
$anggota->pinjam();
$anggota->pinjam();
$anggota->pinjam();

if ($anggota->pinjam()) {
    echo 'pinjam keempat berhasil', "\n";
} else {
    echo 'pinjam keempat ditolak, batas ', Anggota::BATAS_PINJAM, ' tercapai', "\n";
}
echo 'Status kelas: ', Anggota::STATUS_AKTIF, "\n";
text Keluaran
Batas pinjam: 3
pinjam keempat ditolak, batas 3 tercapai
Status kelas: aktif

Late static binding#

Kata kunci self:: menunjuk kelas tempat kode itu ditulis, dan penentuannya selesai saat program dimuat. Perilaku ini menjadi masalah ketika kelas turunan mendefinisikan ulang anggota static yang sama, karena pemanggilan metode induk melalui self:: tetap membaca anggota milik induk. PHP menyediakan late static binding melalui static::, yaitu penunjuk yang diselesaikan pada saat pemanggilan berlangsung, sehingga kelas yang benar-benar dipanggil itulah yang dipakai.

Skrip berikut mendefinisikan kelas Katalog dengan dua metode, satu memakai self::$label dan satu lagi memakai static::$label. Kelas KatalogMedia kemudian mewarisi keduanya dengan label yang berbeda. Kedua metode dipanggil dari KatalogMedia, dan keluarannya berbeda satu sama lain.

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

class Katalog
{
    public static string $label = 'Katalog umum';

    public static function pakaiSelf(): string
    {
        return self::$label;
    }

    public static function pakaiStatic(): string
    {
        return static::$label;
    }
}

class KatalogMedia extends Katalog
{
    public static string $label = 'Katalog media';
}

echo KatalogMedia::pakaiSelf(), "\n";
echo KatalogMedia::pakaiStatic(), "\n";
text Keluaran
Katalog umum
Katalog media

Baris pertama menampilkan Katalog umum karena self::$label pada tubuh pakaiSelf() terikat ke kelas Katalog, tempat kode itu ditulis. Baris kedua menampilkan Katalog media karena static::$label menunggu sampai pemanggilan terjadi, dan pada saat itu kelas yang dipanggil adalah KatalogMedia. Perilaku yang sama juga berlaku pada static::metode() untuk memanggil metode static yang ditimpa di kelas turunan, serta pada new static untuk membuat objek dari kelas yang benar-benar dipanggil.

Kesalahan umum#

  • Memakai $this di dalam metode static. Metode static tidak berjalan atas nama objek mana pun, sehingga $this tidak tersedia di dalamnya dan kode seperti itu gagal sebelum program berjalan. Apabila metode memang perlu membaca keadaan objek, jadikan metode itu metode biasa, bukan metode static.
  • Mengakses properti static melalui objek. Tulisan $anggota->jumlah untuk properti static tidak membaca anggota static yang dimaksud dan memicu peringatan properti tidak terdefinisi. Gunakan Anggota::$jumlah, dan panggil metode static melalui nama kelasnya agar maksudnya terbaca.
  • Mengira self:: mengikuti kelas yang dipanggil. Metode induk yang memakai self:: selalu merujuk ke kelas induknya meskipun dipanggil dari kelas turunan, sehingga pembaruan anggota static di turunan tidak terlihat. Pilih static:: apabila perilakunya harus mengikuti kelas pemanggil.
  • Menyimpan data khusus permintaan di properti static. Dalam aplikasi web, properti static bertahan selama proses berjalan dan dibagi oleh seluruh permintaan yang terjadi di proses itu. Akibatnya, data satu pengguna dapat bocor ke pengguna lain apabila penempatannya keliru. Data yang melekat pada satu permintaan atau satu pengguna ditempatkan pada objek atau penyimpanan yang dirancang untuk itu.

Ringkasan#

  • Anggota static melekat pada kelas, diakses melalui Kelas::anggota, dan hanya mempunyai satu salinan untuk seluruh program, sedangkan $this tidak tersedia di dalam metode static.
  • Konstanta kelas menyimpan nilai tetap bersama dengan visibilitas yang dapat diatur, dan menggantikan angka atau teks ajaib yang tersebar di banyak tempat.
  • self:: terikat ke kelas tempat kode ditulis, sedangkan static:: dengan late static binding terikat ke kelas yang benar-benar dipanggil, sehingga keduanya dapat menghasilkan keluaran yang berbeda pada pewarisan.
  • Properti static adalah keadaan bersama, sehingga pemakaiannya harus disengaja dan tidak boleh menggantikan keadaan yang seharusnya milik objek.

Referensi#