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"; }
}
?>