設計模式是解決特定問題的可復用方案。PHP 開發中最常落地的三大模式——單例、工廠、觀察者——涵蓋資源控制、物件創建解耦、事件驅動架構三大核心需求。本文提供生產級實作代碼與應用場景分析。
適用場景:資料庫連線、配置管理、日誌記錄器、快取客戶端。
<?php
final class Database
{
private static ?self $instance = null;
private PDO $pdo;
private function __construct(array $config)
{
$dsn = "mysql:host={$config['host']};dbname={$config['dbname']};charset=utf8mb4";
$this->pdo = new PDO($dsn, $config['user'], $config['pass'], [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
]);
}
public static function getInstance(array $config = []): self
{
if (self::$instance === null) {
if (empty($config)) { throw new LogicException('首次呼叫需傳入配置'); }
self::$instance = new self($config);
}
return self::$instance;
}
private function __clone() {} // 禁止克隆
private function __wakeup() {} // 禁止反序列化
public function getPdo(): PDO { return $this->pdo; }
}
// 使用
$db = Database::getInstance($config)->getPdo();
適用場景:支援多種驅動(資料庫、快取、儲存)、依據配置動態實例化、統一建構複雜物件。
<?php
interface LoggerInterface { public function log(string $level, string $msg): void; }
class FileLogger implements LoggerInterface {
public function __construct(private string $path) {}
public function log(string $level, string $msg): void {
file_put_contents($this->path, "[$level] $msg\n", FILE_APPEND | LOCK_EX);
}
}
class SyslogLogger implements LoggerInterface {
public function log(string $level, string $msg): void {
syslog(LOG_INFO, "[$level] $msg");
}
}
class LoggerFactory
{
public static function create(string $driver, array $config = []): LoggerInterface
{
return match ($driver) {
'file' => new FileLogger($config['path'] ?? '/var/log/app.log'),
'syslog' => new SyslogLogger(),
default => throw new InvalidArgumentException("Unknown logger: $driver"),
};
}
}
// 使用
$logger = LoggerFactory::create('file', ['path' => '/var/log/myapp.log']);
$logger->log('INFO', 'Application started');
適用場景:用戶註冊後發送歡迎信、寫入審計日誌、更新搜尋索引、清除快取等副作用邏輯。
<?php
interface EventListener { public function handle(string $event, array $payload): void; }
class EventDispatcher
{
/** @var array */
private array $listeners = [];
public function subscribe(string $event, EventListener $listener): void
{
$this->listeners[$event][] = $listener;
}
public function dispatch(string $event, array $payload = []): void
{
foreach ($this->listeners[$event] ?? [] as $listener) {
$listener->handle($event, $payload);
}
}
}
// 具體監聽器
class WelcomeEmailListener implements EventListener {
public function handle(string $event, array $payload): void {
if ($event === 'user.registered') {
mail($payload['email'], 'Welcome!', "Hi {$payload['name']}...");
}
}
}
class AuditLogListener implements EventListener {
public function handle(string $event, array $payload): void {
file_put_contents('/var/log/audit.log', json_encode([$event, $payload, time()]) . "\n", FILE_APPEND);
}
}
// 組裝
$dispatcher = new EventDispatcher();
$dispatcher->subscribe('user.registered', new WelcomeEmailListener());
$dispatcher->subscribe('user.registered', new AuditLogListener());
// 觸發
$dispatcher->dispatch('user.registered', ['id' => 123, 'name' => 'John', 'email' => 'john@example.com']);
| 需求 | 推薦模式 | 核心關鍵字 |
|---|---|---|
| 全域唯一、延遲初始化、受控存取 | 單例 | private constructor, static getInstance() |
| 依條件創建同介面不同實現、隱藏建構細節 | 工廠 | interface, factory method, configuration driven |
| 一對多通知、鬆耦合、事件驅動 | 觀察者 | subscribe, dispatch, listener, event |
掌握三大模式,即可應對 80% 以上的架構級設計決策。切記:模式是手段,解決問題才是目的,勿為用模式而用模式。