2012-02-05 93 views
2

我想以某種方式隱藏父級方法,以便爲在父級上定義的方法調用子類的__call魔術方法。例如:PHP:用__call覆蓋父級方法

class C { 
    function foo() { echo "foo\n"; } 
} 

class D extends C { 
    function __call($method, $args) { echo "called $name\n"; } 
} 

$d = new D(); 
$d->foo(); 

// desired result: called foo 
// actual result: foo 

我檢查了rename_function和override_function,但那些不適用於方法。 ReflectionMethod有一個我嘗試過的setAccessible方法,但是這似乎只在你使用ReflectionMethod實例來調用方法時才起作用。

背景:試圖有一個可以利用PHP的類型檢查的RPC代理類。所以,如果我有一個RPCFoo,我可以使用type hinting或instanceof來強制類型,以便我可以檢查($ RPCFoo實例Foo)。

編輯:基類應該是能夠直接使用,無需代理。這樣代理可以成爲系統配置的一部分,而不是代碼。認爲多個服務器都具有相同的代碼庫,但能夠爲每個服務器分配特定的任務。如果本地服務器不處理所請求的服務,則類加載器將返回代理而不是基類。如果本地服務器處理所請求的服務,它將返回基類。

再次編輯:提出的方法是可行的,但隱藏的基類的從IDE和反射所設計的接口。我試圖使代理實現變得乾淨,以便只需從基類繼承並實現代理接口。爲了維護基類接口,代理開發人員必須重新實現所有公共和受保護的方法以進行遠程調用。然後,在基類中更新某些內容時,代理也必須更新。最後,我認爲我只是想去寫一個使用反射的代理生成器來爲開發人員做這件事。

感謝您的回覆!

回答

2

你必須訪問設置爲foo方法private

class C { 
    private function foo() { 
     echo "foo\n"; 
    } 
    public function __call($method, $args) { 
     if(is_callable(array($this,$method))) { 
      return call_user_func_array(array($this,$method), $args); 
     } else { 
      trigger_error("Call to undefined method '{$method}'"); 
     } 
    } 
} 
+0

然後,基類不能沒有代理使用。 – 2012-02-05 19:15:06

+0

它可以,但你必須在父類中添加神奇的'__call'方法並從那裏調用被調用的方法。看到我的編輯答案 – 2012-02-05 19:42:22

+4

trigger_error ......在2012年...使用的例外) – meze 2012-02-05 19:59:43

0
class C { 

    public function __call($method, $args) { 
     return call_user_func_array(array(__CLASS__ ,$method), $args); 
    } 

    protected function foo() { echo "foo<br />"; } 
} 

class D extends C { 
    function __call($method, $args) { echo "called $method<br/>"; } 
} 

$d = new D(); 
$d->foo(); 

$c = new C(); 
$c->foo(); 
+0

看起來像我被毆打它 – 2012-02-05 19:49:34

+0

受保護的方法將被繼承和通常被稱爲,而且使用'__CLASS__'或'self'在'call_user_func_array'將靜態調用此方法 – 2012-02-05 20:12:30

+0

是的,它會靜態調用該方法 - 我原本以爲靜態方法將是一個要求,但它不是,並且將__CLASS__'更改爲'$ this'不會影響結果。除非有很好的理由,否則我通常會比'private'更喜歡'protected'。我認爲這裏的區別在於,公共方法被優先調用,這就是爲什麼「私有」或「受保護」應該起作用。 – 2012-02-05 20:31:45

0

我知道這個問題是有點老了,但我得到了它的工作,所以我在這裏發佈,以幫助面臨着同樣的人問題。

我的解決方案來超越魔術__call)母公司方法(方法:

public function foo($p1, $p2, $p3) 
{ 
    if (get_class($this) == __CLASS__) { 
     /* Do stuff here */ 
    } elseif (method_exists($this, '__call')) { 
     return call_user_func_array([$this, '__call'], ['foo', func_get_args()]); 
    } 

    return false; 
} 

唯一的限制是父類本身不能有一個神奇的__call()方法,否則它會調用__call( )方法而不是擴展的子類。