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

PHP 反射機制實作委托模式完整指南

     編輯:PHP 相關知識

委托模式在 PHP 中的應用

委托模式是軟體設計模式中的基礎技巧:接收請求的物件將處理邏輯委托給另一個物件執行。許多進階模式(狀態、策略、訪問者)本質上都是委托模式在特定場景的應用。PHP 5.3+ 的反射機制讓動態委托成為可能。

核心概念

  • 委托者:接收外部呼叫,內部持有被委托物件陣列
  • 被委托者:實際執行業務邏輯的物件
  • __call() 魔術方法:攔截不存在的方法呼叫,透過反射轉發給被委托者

基礎實作:單一委托

<?php
class Fruit {
    public function callFruit() {
        echo "Generate an Apple";
    }
}

class FruitDelegator {
    private $targets = array();

    public function __construct() {
        $this->targets[] = new Fruit();
    }

    public function __call($name, $args) {
        foreach ($this->targets as $obj) {
            $reflection = new ReflectionClass($obj);
            if ($method = $reflection->getMethod($name)) {
                if ($method->isPublic() && !$method->isAbstract()) {
                    return $method->invoke($obj, $args);
                }
            }
        }
        throw new BadMethodCallException("Method $name not found in delegated objects");
    }
}

// 使用範例
$obj = new FruitDelegator();
$obj->callFruit();  // 輸出: Generate an Apple
?>

進階實作:動態多重委托

<?php
class Color {
    public function callColor() {
        echo "Generate Red";
    }
}

class Size {
    public function callSize() {
        echo "Size: Large";
    }
}

class MultiDelegator {
    private $targets = array();

    public function addObject($obj) {
        $this->targets[] = $obj;
    }

    public function __call($name, $args) {
        foreach ($this->targets as $obj) {
            $reflection = new ReflectionClass($obj);
            if ($method = $reflection->getMethod($name)) {
                if ($method->isPublic() && !$method->isAbstract()) {
                    return $method->invoke($obj, $args);
                }
            }
        }
        throw new BadMethodCallException("Method $name not found in any delegated object");
    }
}

// 使用範例
$delegator = new MultiDelegator();
$delegator->addObject(new Color());
$delegator->addObject(new Size());

$delegator->callColor();  // 輸出: Generate Red
$delegator->callSize();   // 輸出: Size: Large
?>

反射機制關鍵點解析

方法/屬性用途
ReflectionClass::getMethod()取得方法反射物件,可檢查可見性、參數、回傳型別等
ReflectionMethod::isPublic()確認方法為 public,避免誤呼叫 protected/private 方法
ReflectionMethod::isAbstract()排除抽象方法,防止實例化錯誤
ReflectionMethod::invoke()動態呼叫方法,支援參數陣列傳遞

實務應用場景

  1. 插件系統:核心類委托給多個插件物件,實現事件鉤子機制
  2. 適配器模式:統一不同第三方庫的介面,委托給對應適配器
  3. 動態代理:AOP 切面編程,在方法呼叫前後注入日誌、事務、快取邏輯
  4. 測試雙工:單元測試時委托給 Mock 物件,隔離外部依賴

效能與注意事項

  • 反射呼叫比直接呼叫慢 10-50 倍,高頻路徑建議快取 ReflectionMethod 物件
  • PHP 8.0+ 可搭配 #[ReturnTypeWillChange] 屬性處理回傳型別协变
  • 嚴謹檢查方法存在性與可見性,避免暴露內部敏感方法
  • 考慮使用 method_exists() + call_user_func_array() 簡化輕量級場景

現代替代方案

PHP 7.4+ 引入 箭頭函數 與 First-class callable,PHP 8.1+ 支援 new class() 匿名類,可構建更優雅的委托結構:

<?php
// PHP 8.1+ 現代寫法
$delegator = new class {
    private array $targets = [];

    public function add(object $obj): self {
        $this->targets[] = $obj;
        return $this;
    }

    public function __call(string $name, array $args) {
        foreach ($this->targets as $target) {
            if (method_exists($target, $name)) {
                return $target->$name(...$args);
            }
        }
        throw new BadMethodCallException("$name not found");
    }
};

$delegator->add(new Color())->add(new Size());
$delegator->callColor();
?>
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved