PHP 介面 (Interface)
介面定義了類別必須實作的方法,但不包含實作內容。介面用於建立契約,確保類別具有特定的行為。
定義介面
<?php
interface Printable {
public function print(): string;
}
class Document implements Printable {
public function __construct(
private string $content
) {}
public function print(): string {
return $this->content;
}
}
class Image implements Printable {
public function __construct(
private string $path
) {}
public function print(): string {
return "[Image: {$this->path}]";
}
}
?>
實作多個介面
<?php
interface Readable {
public function read(): string;
}
interface Writable {
public function write(string $data): void;
}
interface Closeable {
public function close(): void;
}
class File implements Readable, Writable, Closeable {
private $handle;
public function __construct(string $path, string $mode) {
$this->handle = fopen($path, $mode);
}
public function read(): string {
return fread($this->handle, 1024);
}
public function write(string $data): void {
fwrite($this->handle, $data);
}
public function close(): void {
fclose($this->handle);
}
}
?>
介面繼承
介面可以繼承其他介面:
<?php
interface Countable {
public function count(): int;
}
interface Collection extends Countable {
public function add($item): void;
public function remove($item): void;
public function contains($item): bool;
}
class ArrayList implements Collection {
private array $items = [];
public function count(): int {
return count($this->items);
}
public function add($item): void {
$this->items[] = $item;
}
public function remove($item): void {
$key = array_search($item, $this->items);
if ($key !== false) {
unset($this->items[$key]);
}
}
public function contains($item): bool {
return in_array($item, $this->items);
}
}
?>
介面常數
介面可以包含常數:
<?php
interface Status {
public const PENDING = 'pending';
public const ACTIVE = 'active';
public const COMPLETED = 'completed';
}
class Task implements Status {
private string $status = self::PENDING;
public function activate(): void {
$this->status = self::ACTIVE;
}
}
echo Status::PENDING; // pending
?>
型別提示
介面可以作為型別提示:
<?php
interface Logger {
public function log(string $message): void;
}
class ConsoleLogger implements Logger {
public function log(string $message): void {
echo "[LOG] $message\n";
}
}
class FileLogger implements Logger {
public function log(string $message): void {
file_put_contents('app.log', $message . "\n", FILE_APPEND);
}
}
class Application {
public function __construct(
private Logger $logger
) {}
public function run(): void {
$this->logger->log("Application started");
}
}
// 可以注入任何實作 Logger 的物件
$app = new Application(new ConsoleLogger());
$app->run();
?>
內建介面
PHP 提供了許多內建介面:
<?php
// Iterator - 可迭代
class NumberRange implements Iterator {
private int $current;
public function __construct(
private int $start,
private int $end
) {
$this->current = $start;
}
public function current(): int { return $this->current; }
public function key(): int { return $this->current - $this->start; }
public function next(): void { $this->current++; }
public function rewind(): void { $this->current = $this->start; }
public function valid(): bool { return $this->current <= $this->end; }
}
foreach (new NumberRange(1, 5) as $num) {
echo $num; // 1 2 3 4 5
}
// Countable - 可計數
class Collection implements Countable {
private array $items = [];
public function count(): int {
return count($this->items);
}
}
// ArrayAccess - 陣列存取
class Config implements ArrayAccess {
private array $data = [];
public function offsetExists($offset): bool {
return isset($this->data[$offset]);
}
public function offsetGet($offset): mixed {
return $this->data[$offset] ?? null;
}
public function offsetSet($offset, $value): void {
$this->data[$offset] = $value;
}
public function offsetUnset($offset): void {
unset($this->data[$offset]);
}
}
$config = new Config();
$config['debug'] = true;
echo $config['debug']; // 1
?>
介面 vs 抽象類別
| 特性 | 介面 | 抽象類別 |
|---|---|---|
| 實作 | 無(PHP 8+ 可有預設方法) | 可以有 |
| 屬性 | 只能有常數 | 可以有 |
| 建構子 | 無 | 可以有 |
| 多重繼承 | 支援 | 不支援 |
<?php
// 使用介面:定義能力
interface Flyable {
public function fly(): void;
}
interface Swimmable {
public function swim(): void;
}
class Duck implements Flyable, Swimmable {
public function fly(): void { echo "Flying\n"; }
public function swim(): void { echo "Swimming\n"; }
}
?>