Connecting Components via Contracts
Apa itu Interface?
Stopkontak listrik adalah sebuah Interface.
Interface adalah struktur pemrograman yang mendefinisikan KONTRAK method apa saja yang harus dimiliki oleh sebuah class, tanpa mendefinisikan cara kerjanya.
Semua method dalam interface otomatis bersifat public dan abstract.
Keyword: interface & implements
Gunakan keyword interface.
interface Logger {
public function log($message);
public function error($message);
}
Perhatikan: Tidak ada body method {}.
Gunakan keyword implements pada class.
class FileLogger implements Logger {
public function log($message) {
// Tulis ke file log.txt
file_put_contents('log.txt', $message, FILE_APPEND);
}
public function error($message) {
// Tulis error
$this->log("[ERROR] " . $message);
}
}
Jika sebuah class meng-implements sebuah interface, class tersebut WAJIB
mendefinisikan ulang (override) SEMUA method yang ada di interface tersebut.
Jika kurang satu saja, akan terjadi Fatal Error!
Kita bisa membuat implementasi lain yang berbeda total.
class DatabaseLogger implements Logger {
public function log($message) {
// Insert ke tabel logs di database
$db->query("INSERT INTO logs ...");
}
public function error($message) {
// ...
}
}
Melampaui Batas Abstract Class
Di PHP, sebuah class hanya bisa extends SATU parent class.
class SmartPhone extends Phone, Computer { // ERROR! }
Sebuah class bisa meng-implements BANYAK interface sekaligus. Ini adalah cara PHP meniru Multiple Inheritance.
class SmartPhone implements Phone, Computer, Camera {
// Wajib implementasi method dari Phone
// Wajib implementasi method dari Computer
// Wajib implementasi method dari Camera
}
interface CanFly {
public function fly();
}
interface CanSwim {
public function swim();
}
class Duck implements CanFly, CanSwim {
public function fly() { echo "Bebek terbang rendah"; }
public function swim() { echo "Bebek berenang"; }
}
Kapan Pakai Yang Mana?
| Fitur | Interface | Abstract Class |
|---|---|---|
| Method Body | Tidak Boleh | Boleh (Partial Implementation) |
| Properties | Hanya Konstanta | Boleh Variable ($state) |
| Inheritance | Multiple (implements) | Single (extends) |
| Keyword | implements | extends |
Gunakan Interface ketika Anda ingin mendefinisikan KEMAMPUAN (Capability) yang bisa dimiliki oleh berbagai class yang tidak saling berhubungan.
Contoh: Loggable, Countable, JsonSerializable.
Gunakan Abstract Class ketika Anda ingin membuat TEMPLATE DASAR untuk class-class yang memiliki hubungan erat ("is-a").
Contoh: User (abstract) -> Admin, Member.
Type Hinting dengan Interface
Kekuatan utama interface bukan pada pembuatannya, tapi pada penggunaannya sebagai Type Hint di fungsi/method.
class UserProfile {
public function update(FileLogger $logger) {
// ... update profile
$logger->log("Profile updated");
}
}
Masalah: Fungsi ini HANYA bisa menerima FileLogger. Kalau mau ganti ke
DatabaseLogger, harus ubah kode!
class UserProfile {
// Type Hint ke Interface, bukan Class konkret
public function update(Logger $logger) {
// ... update profile
$logger->log("Profile updated");
}
}
Sekarang fungsi ini bisa menerima APAPUN, asalkan benda itu adalah Logger.
Ini adalah dasar dari prinsip Dependency Injection dan Inversion of Control.
$fileLog = new FileLogger();
$dbLog = new DatabaseLogger();
$profile = new UserProfile();
// Bisa pakai File
$profile->update($fileLog);
// Bisa pakai Database, tanpa ubah kode UserProfile!
$profile->update($dbLog);
Contoh Dunia Nyata
Aplikasi kita saat ini menggunakan MySQL. Tapi mungkin tahun depan kita ingin pindah ke MongoDB atau Firebase.
Jika kode query MySQL tersebar di mana-mana, migrasi akan sangat sulit.
interface UserRepository {
public function all();
public function find($id);
public function save($data);
}
class EloquentUserRepository implements UserRepository {
public function find($id) {
return User::find($id); // Eloquent ORM
}
// ...
}
class MongoUserRepository implements UserRepository {
public function find($id) {
return $this->mongo->collection('users')->findOne(['_id' => $id]);
}
// ...
}
class UserController {
private $repo;
// Controller tidak peduli databasenya apa!
public function __construct(UserRepository $repo) {
$this->repo = $repo;
}
public function show($id) {
$user = $this->repo->find($id);
return view('user.profile', ['user' => $user]);
}
}
PHP sendiri menyediakan banyak interface bawaan yang sakti.
Iterator: Membuat object bisa di-looping dengan foreach.JsonSerializable: Mengatur format JSON saat object di-json_encode.Countable: Membuat object bisa dihitung dengan count().
class User implements JsonSerializable {
public function jsonSerialize() {
return [
'id' => $this->id,
'name' => $this->name,
// Password tidak ikut diserialisasi!
];
}
}
echo json_encode(new User());
Interface bisa memiliki konstanta, yang otomatis diwariskan ke class implementornya.
interface Status {
const ACTIVE = 1;
const INACTIVE = 0;
}
class User implements Status {
public function activate() {
$this->status = self::ACTIVE;
}
}
Connection Terminated.