Interface adalah kontrak antarmuka yang menetapkan metode apa saja yang wajib dimiliki sebuah kelas, tanpa menentukan bagaimana metode itu dikerjakan. Topik ini membahas deklarasi interface dan penerapannya pada kelas, penggunaan nama interface sebagai tipe yang mengaktifkan polimorfisme (polymorphism), serta iterasi atas kumpulan objek yang memenuhi kontrak yang sama. Domain perpustakaan memberi contohnya, yaitu kontrak DapatDipinjam yang dipenuhi oleh koleksi dengan jenis yang berbeda-beda.
Menetapkan kontrak dengan interface#
Deklarasi interface memakai kata kunci interface, dan isinya berupa tanda tangan metode tanpa tubuh. Semua metode di dalamnya berlaku public secara otomatis, sehingga kata kunci visibilitas tidak perlu ditulis, dan kata kunci selain public tidak diperbolehkan. Kelas yang mengikuti kontrak tersebut menyatakannya dengan implements, lalu wajib menyediakan implementasi seluruh metode kontrak dengan tanda tangan yang kompatibel. Kontrak juga boleh memuat konstanta kelas yang diwariskan kepada semua penerapnya.
Hubungan antara kontrak dan penerapnya diperiksa oleh instanceof. Kelas yang menyatakan implements dihitung sebagai objek bertipe interface tersebut, dan pemeriksaan itu berlaku meskipun interface tidak dapat dijadikan objek. Percobaan membuat objek langsung dari sebuah interface memicu Error, sebagaimana ditunjukkan pada akhir skrip berikut.
<?php
declare(strict_types=1);
interface DapatDipinjam
{
public function pinjamkan(): bool;
public function kembalikan(): void;
}
class Buku implements DapatDipinjam
{
public function __construct(
public string $judul,
private int $stok = 2,
) {
}
public function pinjamkan(): bool
{
if ($this->stok < 1) {
return false;
}
$this->stok--;
return true;
}
public function kembalikan(): void
{
$this->stok++;
}
}
$buku = new Buku('Algoritma Dasar');
var_dump($buku instanceof DapatDipinjam);
if ($buku->pinjamkan()) {
echo 'peminjaman dicatat', "\n";
}
$buku->kembalikan();
echo 'koleksi kembali tersedia', "\n";
try {
new DapatDipinjam();
} catch (Throwable $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}bool(true)
peminjaman dicatat
koleksi kembali tersedia
Error: Cannot instantiate interface DapatDipinjamBaris pertama keluaran menegaskan bahwa Buku memenuhi kontrak DapatDipinjam, sedangkan baris error terakhir menunjukkan bahwa kontrak bukan kelas yang dapat dijadikan objek. Perlu dicatat bahwa satu kelas boleh menerapkan lebih dari satu interface sekaligus dengan menulisnya berurutan setelah implements, sehingga kebutuhan kontrak ganda tetap terpenuhi meskipun kelas hanya dapat mewarisi satu induk.
Polimorfisme melalui tipe interface#
Nama interface dapat dipakai sebagai deklarasi tipe pada parameter fungsi, properti, dan nilai kembalian. Konsekuensinya adalah polimorfisme, yaitu satu fungsi dapat menerima objek dari kelas apa pun asalkan memenuhi kontrak yang sama. Fungsi tersebut tidak perlu mengetahui kelas konkretnya. Inilah nilai utama kontrak, karena kode yang ditulis sekali tetap bekerja untuk implementasi yang belum ada saat fungsi tersebut ditulis.
Skrip berikut mendefinisikan kontrak Berlabel beserta fungsi catatLabel() yang menerima parameter bertipe Berlabel. Kelas Buku memenuhi kontrak tersebut dan objeknya dapat diteruskan ke fungsi itu. Kelas Rak tidak memenuhinya, dan pemeriksaan instanceof terhadap objek Rak bernilai false.
<?php
declare(strict_types=1);
interface Berlabel
{
public function label(): string;
}
class Buku implements Berlabel
{
public function __construct(public string $judul)
{
}
public function label(): string
{
return "Buku: {$this->judul}";
}
}
class Rak
{
public function __construct(public string $kode)
{
}
}
function catatLabel(Berlabel $benda): void
{
echo $benda->label(), "\n";
}
$buku = new Buku('Algoritma Dasar');
$rak = new Rak('RAK-A');
catatLabel($buku);
var_dump($buku instanceof Berlabel);
var_dump($rak instanceof Berlabel);Buku: Algoritma Dasar
bool(true)
bool(false)Pemanggilan catatLabel($buku) berhasil karena $buku memenuhi kontrak, dan fungsinya memanggil label() tanpa pernah menyebut kelas Buku. Apabila Rak diteruskan ke fungsi yang sama, PHP menolaknya dengan TypeError karena tipe argumennya tidak memenuhi deklarasi Berlabel. Dengan demikian, pelanggaran kontrak tertangkap sebelum metode yang tidak ada sempat dipanggil.
Iterasi atas implementasi#
Kumpulan objek yang memenuhi kontrak yang sama dapat diiterasi sebagai satu kesatuan, misalnya array yang setiap elemennya memenuhi kontrak DapatDipinjam. Perulangan foreach memproses setiap elemen melalui kontraknya, sehingga kode perulangan tidak berubah ketika jenis koleksi baru ditambahkan. Pola ini membuat penambahan jenis koleksi tidak menyentuh kode peminjaman sama sekali.
Skrip berikut mengumpulkan satu Buku dan satu Laptop ke dalam satu array, lalu mengiterasinya dengan satu perulangan yang sama. Kedua kelas menyediakan logika keadaan yang berbeda, yaitu stok salinan pada Buku dan penanda sedang dipinjam pada Laptop, tetapi keduanya memenuhi kontrak yang sama.
<?php
declare(strict_types=1);
interface DapatDipinjam
{
public function pinjamkan(): bool;
public function kembalikan(): void;
public function label(): string;
}
class Buku implements DapatDipinjam
{
public function __construct(
public string $judul,
private int $stok = 1,
) {
}
public function pinjamkan(): bool
{
if ($this->stok < 1) {
return false;
}
$this->stok--;
return true;
}
public function kembalikan(): void
{
$this->stok++;
}
public function label(): string
{
return "Buku: {$this->judul}";
}
}
class Laptop implements DapatDipinjam
{
private bool $sedangDipinjam = false;
public function __construct(public string $unit)
{
}
public function pinjamkan(): bool
{
if ($this->sedangDipinjam) {
return false;
}
$this->sedangDipinjam = true;
return true;
}
public function kembalikan(): void
{
$this->sedangDipinjam = false;
}
public function label(): string
{
return "Laptop unit {$this->unit}";
}
}
$koleksi = [
new Buku('Algoritma Dasar'),
new Laptop('LP-11'),
];
foreach ($koleksi as $item) {
if ($item->pinjamkan()) {
echo $item->label(), ' dipinjam', "\n";
}
if ($item->pinjamkan()) {
echo $item->label(), ' dipinjam lagi', "\n";
} else {
echo $item->label(), ' tidak tersedia lagi', "\n";
}
}Buku: Algoritma Dasar dipinjam
Buku: Algoritma Dasar tidak tersedia lagi
Laptop unit LP-11 dipinjam
Laptop unit LP-11 tidak tersedia lagiSetiap pasangan baris pada keluaran memperlihatkan peminjaman pertama yang berhasil dan peminjaman kedua yang ditolak, masing-masing dengan alasan yang berbeda di dalam kelasnya. Satu-satunya hal yang dibagikan adalah kontraknya, dan itulah yang membuat perulangan ini dapat menerima jenis koleksi apa pun asalkan kontraknya dipenuhi.
Kesalahan umum#
- Melupakan satu metode kontrak pada kelas penerapnya. Kelas yang tidak menyediakan seluruh metode kontrak gagal dideklarasikan dengan pesan berisi jumlah metode abstrak yang belum terpenuhi. Lengkapi seluruh metodenya, atau nyatakan kelas itu sendiri sebagai kelas abstrak.
- Mengetatkan visibilitas metode implementasi. Metode kontrak berlaku
public, sehingga implementasinya yang ditulisprotectedatauprivatemenggagalkan deklarasi kelas. Visibilitas implementasi dipertahankanpublickarena kontrak menjanjikan akses dari luar. - Mengira interface dapat menyimpan keadaan. Interface tidak memuat properti, sehingga kebutuhan keadaan bersama harus diletakkan di kelas penerapnya atau dipindahkan ke kelas abstrak. Pilih interface untuk kontrak perilaku dan kelas abstrak untuk berbagi implementasi beserta keadaannya.
- Memanggil anggota di luar kontrak pada variabel bertipe interface. Variabel bertipe
DapatDipinjamhanya menjanjikan metode kontraknya, sehingga pemanggilan metode khusus kelas tertentu melalui variabel tersebut menimbulkan error ketika implementasi lain masuk ke jalur yang sama. Tambahkan metode yang diperlukan ke kontraknya, atau periksainstanceofbila jalur khusus memang diperlukan.
Ringkasan#
- Interface menetapkan tanda tangan metode tanpa implementasi, dan kelas yang menyatakan
implementswajib melengkapi seluruh metodenya dengan visibilitaspublic. - Nama interface dipakai sebagai tipe, sehingga satu fungsi menerima implementasi apa pun yang memenuhi kontraknya, dan itulah polimorfisme.
instanceofmemeriksa pemenuhan kontrak per interface, dan satu kelas boleh memenuhi beberapa kontrak sekaligus.- Kumpulan objek yang memenuhi kontrak yang sama dapat diiterasi dengan satu perulangan, dan penambahan implementasi baru tidak mengubah kode perulangannya.
Referensi#
- Object Interfaces — Manual PHP
— Menetapkan aturan deklarasi interface,
implements, dan konstantanya. - instanceof — Manual PHP — Menjelaskan pemeriksaan tipe objek, termasuk terhadap interface.
- Type Declarations — Manual PHP — Menyebut nama interface yang sah dipakai sebagai deklarasi tipe parameter dan kembalian.