<?php
// Interface — method signatures only, no body
interface Drawable {
public function draw(): string;
public function getColor(): string;
}
interface Resizable {
public function resize(float $factor): void;
public function getArea(): float;
}
// Class implements multiple interfaces
class Circle implements Drawable, Resizable {
public function __construct(
private float $radius,
private string $color
) {}
// Must implement ALL methods from Drawable
public function draw(): string {
return "Drawing a {$this->color} circle (r={$this->radius})";
}
public function getColor(): string { return $this->color; }
// Must implement ALL methods from Resizable
public function resize(float $factor): void {
$this->radius *= $factor;
}
public function getArea(): float {
return M_PI * $this->radius ** 2;
}
}
class Square implements Drawable, Resizable {
public function __construct(
private float $side,
private string $color
) {}
public function draw(): string {
return "Drawing a {$this->color} square ({$this->side}x{$this->side})";
}
public function getColor(): string { return $this->color; }
public function resize(float $factor): void { $this->side *= $factor; }
public function getArea(): float { return $this->side ** 2; }
}
$c = new Circle(5.0, "red");
$s = new Square(4.0, "blue");
echo $c->draw(); // "Drawing a red circle (r=5)"
$c->resize(2);
echo $c->getArea(); // ~314.16
// Type hinting with interface
function drawAll(Drawable ...$shapes): void {
foreach ($shapes as $shape) {
echo $shape->draw() . "\n";
}
}
drawAll($c, $s);
<?php
interface Loggable {
public function log(string $message): void;
}
interface Cacheable {
public function cache(string $key, mixed $data): void;
public function getFromCache(string $key): mixed;
}
// Interface can extend other interfaces
interface Repository extends Loggable {
public function findById(int $id): ?array;
public function findAll(): array;
public function save(array $data): bool;
public function delete(int $id): bool;
}
// Implement — must implement all: Loggable + Repository methods
class UserRepository implements Repository {
private array $users = [];
private array $logs = [];
public function log(string $message): void {
$this->logs[] = date("Y-m-d H:i:s") . " — " . $message;
}
public function findById(int $id): ?array {
return $this->users[$id] ?? null;
}
public function findAll(): array { return $this->users; }
public function save(array $data): bool {
$id = $data['id'] ?? count($this->users) + 1;
$this->users[$id] = $data;
$this->log("Saved user #$id");
return true;
}
public function delete(int $id): bool {
if (!isset($this->users[$id])) return false;
unset($this->users[$id]);
$this->log("Deleted user #$id");
return true;
}
}
$repo = new UserRepository();
$repo->save(['id' => 1, 'name' => 'Ko Ko', 'email' => 'ko@example.com']);
$repo->save(['id' => 2, 'name' => 'Ma Ma', 'email' => 'ma@example.com']);
print_r($repo->findAll());
<?php
interface HttpStatus {
const OK = 200;
const CREATED = 201;
const BAD_REQUEST = 400;
const UNAUTHORIZED = 401;
const NOT_FOUND = 404;
const SERVER_ERROR = 500;
}
interface ApiResponse extends HttpStatus {
public function respond(mixed $data, int $status = self::OK): array;
public function error(string $message, int $status = self::BAD_REQUEST): array;
}
class JsonResponse implements ApiResponse {
public function respond(mixed $data, int $status = self::OK): array {
return [
'status' => $status,
'success' => $status < 400,
'data' => $data,
];
}
public function error(string $message, int $status = self::BAD_REQUEST): array {
return [
'status' => $status,
'success' => false,
'error' => $message,
];
}
}
$api = new JsonResponse();
$api->respond(['user' => 'Ko Ko']);
// ['status' => 200, 'success' => true, 'data' => ['user' => 'Ko Ko']]
$api->error("User not found", HttpStatus::NOT_FOUND);
// ['status' => 404, 'success' => false, 'error' => 'User not found']
| Feature | Interface | Abstract Class |
|---|---|---|
| Method implementation | ❌ No | ✅ Can have concrete methods |
| Properties | Constants only | ✅ Full properties |
| Multiple inheritance | ✅ implements many | ❌ extends one only |
| Constructor | ❌ Not allowed | ✅ Allowed |
| Access modifiers | public only | All (public/protected) |
| Use when | "Can do" behavior contract | "Is a" base implementation |
// Rule of thumb: // Interface = "can do" / "is able to" (Printable, Serializable, Drawable) // Abstract = "is a" base (Animal, Shape, Vehicle)
<?php
// Interface-based DI — loosely coupled, easily testable
interface EmailSender {
public function send(string $to, string $subject, string $body): bool;
}
interface SMSSender {
public function sendSMS(string $phone, string $message): bool;
}
class SmtpEmailSender implements EmailSender {
public function send(string $to, string $subject, string $body): bool {
// Real SMTP logic...
echo "SMTP: Sending email to $to\n";
return true;
}
}
class MockEmailSender implements EmailSender {
public array $sent = [];
public function send(string $to, string $subject, string $body): bool {
$this->sent[] = compact('to', 'subject', 'body');
return true;
}
}
class UserService {
public function __construct(private EmailSender $mailer) {}
public function register(string $name, string $email): void {
// save to DB...
$this->mailer->send(
$email,
"Welcome!",
"Hi $name, thanks for registering!"
);
}
}
// Production
$service = new UserService(new SmtpEmailSender());
$service->register("Ko Ko", "ko@example.com");
// Testing — swap implementation easily!
$mock = new MockEmailSender();
$testService = new UserService($mock);
$testService->register("Test", "test@example.com");
print_r($mock->sent); // verify email was "sent"
← PHP 09 | Next: PHP 11 → Traits →