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

深入理解 PHP 介面 存在的意義:解耦、契約與多型實戰範例

     編輯:PHP 綜合知識

許多開發者知道「如何寫介面」,卻不清楚「為什麼要寫介面」。本文透過一個具體的付款情境,示範介面如何實現解耦、定義契約、支援多型替換,並說明介面在團隊協作與架構演進中的核心價值。

情境:支援多種付款方式

系統需支援「現金」、「信用卡」、「Line Pay」等付款方式,未來可能新增「Apple Pay」、「比特幣」。若直接在主程式寫死 if ($type === 'cash') ...,每新增一種就得修改核心邏輯,違反開放封閉原則(OCP)。

1. 定義付款介面:契約

// PayInterface.php
interface PayInterface
{
    // 契約:所有付款方式必須實作 pay() 方法
    public function pay(float $amount): bool;

    // 可選:退款介面(另一個介面,遵循介面隔離原則 ISP)
    // public function refund(string $orderId): bool;
}

2. 具體實作類別:多型

// CashPay.php
class CashPay implements PayInterface
{
    public function pay(float $amount): bool
    {
        echo "以現金支付 $amount 元";
        return true;
    }
}

// CreditCardPay.php
class CreditCardPay implements PayInterface
{
    private $cardNumber;

    public function __construct(string $cardNumber)
    {
        $this->cardNumber = $cardNumber;
    }

    public function pay(float $amount): bool
    {
        echo "以信用卡 {$this->cardNumber} 扣款 $amount 元";
        // 呼叫金流 API...
        return true;
    }
}

// LinePay.php
class LinePay implements PayInterface
{
    public function pay(float $amount): bool
    {
        echo "導向 Line Pay 支付 $amount 元";
        // 產生付款連結、導向...
        return true;
    }
}

3. 高層模組依賴介面:解耦

// OrderService.php
class OrderService
{
    // 建構子注入:依賴抽象(介面),而非具體類別
    public function __construct(private PayInterface $payment) {}

    public function checkout(float $amount): void
    {
        // 業務邏輯:驗證庫存、建立訂單...
        echo "處理訂單中...\n";

        // 委派付款給實作類別,完全不需知道具體是哪一種
        if ($this->payment->pay($amount)) {
            echo "付款成功,訂單成立!\n";
        } else {
            throw new Exception('付款失敗');
        }
    }
}

4. 使用端組裝:執行期決定具體實作

// index.php
require_once 'vendor/autoload.php';

// 情境 A:使用者選擇現金
$service = new OrderService(new CashPay());
$service->checkout(1500);

// 情境 B:使用者選擇信用卡
$service = new OrderService(new CreditCardPay('4242-4242-4242-4242'));
$service->checkout(3000);

// 情境 C:從設定檔/資料庫動態決定
$paymentClass = $_ENV['DEFAULT_PAYMENT'] ?? 'CashPay'; // 例如 'LinePay'
$payment = new $paymentClass();
$service = new OrderService($payment);
$service->checkout(500);

介面存在的三大核心意義

核心價值說明上例體現
解耦高層模組不依賴低層實作細節,雙方僅透過介面溝通OrderService 完全不知 CashPay/CreditCardPay 存在
契約強制所有實作類別遵守相同方法簽名,編譯/執行期保證相容性所有付款類別必須有 pay(float): bool
多型執行期可動態替換實作,支援策略模式、外掛架構、A/B 測試同一 OrderService 可搭配任一付款方式

常見誤區與澄清

  • 誤區:「介面只是多寫一層程式碼,沒有實際功能。」
    澄清:介面是架構邊界,保護核心業務邏輯不被外部實作細節汙染,也是單元測試 Mock 的基礎。
  • 誤區:「所有類別都要有介面。」
    澄清:僅在跨層級依賴(Controller→Service、Service→Repository)、多重實作可能、第三方整合 時定義介面。單純的 Value Object、DTO、Entity 不需介面。
  • PHP 8.1+ 新特性:interface 可定義 public function defaultMethod(): void { ... } 提供預設實作,減少樣板程式碼。

進階:介面隔離原則 (ISP) 實踐

若付款方式「不支援退款」,不應強迫實作 refund()。拆分介面:

interface PayableInterface      { public function pay(float $amount): bool; }
interface RefundableInterface  { public function refund(string $orderId): bool; }

class CashPay implements PayableInterface { ... } // 僅實作 Payable
class CreditCardPay implements PayableInterface, RefundableInterface { ... } // 兩者皆實作

這樣 OrderService 僅依賴 PayableInterface,退款服務依賴 RefundableInterface,職責更單一。

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