首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 介面與抽象類別深度解析:契約導向設計與程式碼復用

     編輯:PHP 相關知識

介面與抽象類別是 PHP 物件導向設計的核心工具,雖有重疊但解決不同問題。本文透過電商商店場景深度對比,說明何時使用哪一種。

核心差異速查表

特性介面抽象類別
關鍵字interfaceabstract class
方法實作不可有實作 (PHP 8.0 前)可有具體實作
屬性不可有 (PHP 8.0+ 可有常數)可有屬性、常數
建構子不可有可有
繼承關係implements (多重實作)extends (單一繼承)
設計意圖定義「契約/能力」提供「基礎實作/模板」
存取修飾詞隱含 publicpublic/protected/private

場景:電商商店系統

1. 介面:定義契約

<?php
// 契約:所有商店必須具備的能力
interface ShopInterface {
    public function buy(int $productId, int $quantity): Order;
    public function sell(int $productId, int $quantity): Receipt;
    public function view(int $productId): Product;
    public function getInventory(): array;
}

// 另一個契約:可計價
interface Pricable {
    public function getPrice(): float;
    public function setPrice(float $price): void;
}

// 多重實作:實體店同時實作商店介面與計價介面
class PhysicalStore implements ShopInterface, Pricable {
    private array $inventory = [];
    
    public function buy(int $productId, int $quantity): Order { /* ... */ }
    public function sell(int $productId, int $quantity): Receipt { /* ... */ }
    public function view(int $productId): Product { /* ... */ }
    public function getInventory(): array { return $this->inventory; }
    public function getPrice(): float { /* ... */ }
    public function setPrice(float $price): void { /* ... */ }
}
?>

2. 抽象類別:提供基礎實作

<?php
// 基礎商店:共用邏輯(連線、日誌、快取)
abstract class BaseShop {
    protected PDO $db;
    protected Logger $logger;
    protected Cache $cache;
    
    public function __construct(PDO $db, Logger $logger, Cache $cache) {
        $this->db = $db;
        $this->logger = $logger;
        $this->cache = $cache;
    }
    
    // 具體實作:所有子類共用
    protected function log(string $action, array $data): void {
        $this->logger->info($action, $data + ['shop' => static::class]);
    }
    
    protected function getCached(string $key, callable $fallback, int $ttl = 300): mixed {
        return $this->cache->remember($key, $fallback, $ttl);
    }
    
    // 模板方法:定義流程,子類實作細節
    public function buy(int $productId, int $quantity): Order {
        $this->validateStock($productId, $quantity);
        $order = $this->createOrder($productId, $quantity);
        $this->deductStock($productId, $quantity);
        $this->log('buy', ['product' => $productId, 'qty' => $quantity]);
        return $order;
    }
    
    // 抽象方法:強制子類實作
    abstract protected function validateStock(int $productId, int $quantity): void;
    abstract protected function createOrder(int $productId, int $quantity): Order;
    abstract protected function deductStock(int $productId, int $quantity): void;
}

// 子類只需實作業務細節
class OnlineShop extends BaseShop {
    protected function validateStock(int $productId, int $quantity): void {
        $stock = $this->getCached("stock:$productId", fn() => $this->fetchStock($productId));
        if ($stock < $quantity) throw new Exception('庫存不足');
    }
    
    protected function createOrder(int $productId, int $quantity): Order {
        return Order::create(['product_id' => $productId, 'quantity' => $quantity]);
    }
    
    protected function deductStock(int $productId, int $quantity): void {
        $this->db->exec("UPDATE products SET stock = stock - $quantity WHERE id = $productId");
        $this->cache->forget("stock:$productId");
    }
}
?>

3. 組合使用:介面 + 抽象類別

<?php
// 介面定義對外契約
interface ShopInterface { /* ... */ }

// 抽象類別提供基礎建設
abstract class BaseShop { /* ... */ }

// 具體實作
class OnlineShop extends BaseShop implements ShopInterface { /* ... */ }
class PhysicalStore extends BaseShop implements ShopInterface { /* ... */ }

// 依賴介面而非具體類別(依賴倒置原則)
class OrderService {
    public function __construct(
        private ShopInterface $shop  // 可注入任何實作
    ) {}
    
    public function processBuy(int $productId, int $qty): Order {
        return $this->shop->buy($productId, $qty);
    }
}
?>

決策流程圖

需要定義「必須做什麼」嗎?
  ├─ 是 → 使用 interface
  │        └─ 需要多重實作? → interface (支援 implements A, B, C)
  │
  └─ 需要提供「共用怎麼做」嗎?
       ├─ 是 → 使用 abstract class
       │        ├─ 有建構子邏輯? → abstract class
       │        ├─ 有 protected 共用方法? → abstract class
       │        └─ 模板方法模式? → abstract class
       │
       └─ 兩者都需要? → interface + abstract class 組合

PHP 8.0+ 新特性

  • 介面可定義 public const 常數
  • 介面方法可有 default 實作(public function foo(): int { return 1; })
  • mixed 型別提示支援介面/抽象類別

常見反模式

❌ 過度使用抽象類別
將所有共用方法塞進 BaseClass,導致繼承樹過深、耦合度高。
✅ 改用 Trait 組合橫向關注點,或服務類別注入。
❌ 介面定義太細碎
每個方法一個介面,導致實作類別 implements 10+ 介面。
✅ 依功能內聚定義介面(如 ShopInterface、PayableInterface、ShippableInterface)。

介面定義「外部契約」,抽象類別提供「內部骨架」。善用兩者組合,配合依賴注入,能建立高內聚、低耦合、可測試的系統架構。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved