2010-06-10 68 views
13

我使用WordPress作爲CMS,我想擴展它的一個類而不必從另一個類繼承;即我只是想更多的方法 「增加」 的那類:如何將方法添加到PHP中的現有類?

class A { 

    function do_a() { 
     echo 'a'; 
    } 
} 

則:

function insert_this_function_into_class_A() { 
    echo 'b'; 
} 

和(插入後者分爲A類的一些方法):

A::insert_this_function_into_class_A(); # b 

這甚至可能在頑強的PHP?

+0

「頑強PHP」? – Artefacto 2010-06-10 05:47:17

+0

正在編輯類源代碼的一個選項? – 2010-06-10 05:48:00

+0

標題有誤導性; 「延長」是指繼承。我已經改變它來更好地反映你的問題。 – Artefacto 2010-06-10 05:53:11

回答

17

如果您只需要訪問類的公共API,你可以使用一個Decorator

class SomeClassDecorator 
{ 
    protected $_instance; 

    public function myMethod() { 
     return strtoupper($this->_instance->someMethod()); 
    } 

    public function __construct(SomeClass $instance) { 
     $this->_instance = $instance; 
    } 

    public function __call($method, $args) { 
     return call_user_func_array(array($this->_instance, $method), $args); 
    } 

    public function __get($key) { 
     return $this->_instance->$key; 
    } 

    public function __set($key, $val) { 
     return $this->_instance->$key = $val; 
    } 

    // can implement additional (magic) methods here ... 
} 

然後包SomeClass的實例:

$decorator = new SomeClassDecorator(new SomeClass); 

$decorator->foo = 'bar';  // sets $foo in SomeClass instance 
echo $decorator->foo;   // returns 'bar' 
echo $decorator->someMethod(); // forwards call to SomeClass instance 
echo $decorator->myMethod(); // calls my custom methods in Decorator 

如果您需要訪問到protected API,你必須使用繼承。如果您需要訪問private API,則必須修改類文件。儘管繼承方式沒問題,但修改類文件可能會在更新時遇到問題(您將失去所有修補程序)。但兩者比使用runkit更可行。

+1

太好了!這不僅適用於將新方法添加到類中,而且在'延伸'不是選項時覆蓋它們。 – juanra 2015-04-29 11:09:12

3

你可以使用the runkit extension來做這件事,但你應該真的考慮定期繼承。

請參閱runkit_method_add

+0

...雖然runkit不過是一款玩具。 – johannes 2010-06-10 05:53:56

+1

@johannes調試時有時很有用。但這就是我推薦的原因,但這並不妨礙我實際回答問題。 – Artefacto 2010-06-10 06:01:40

+1

注意手冊頁上的大的紅色「實驗」警告?不推薦用於任何生產用途... – selfawaresoup 2010-06-10 06:25:52

2

如果有問題的類實現__call魔術,那麼這是可能的,而且很容易。如果你想知道這是如何工作的,我建議你閱讀Extending objects with new methods at runtime

+0

可能,但它會增加很多令人討厭的代碼,以後可能難以維護。特別是「$ func = $ foo-> baz; $ func();」可能有失敗寫在它的全部。 :) – selfawaresoup 2010-06-10 06:28:08

+0

我知道這很難維護,這將是地獄調試,我當然不會推薦使用它,但它*是*可能的:第。 – wimvds 2010-06-10 07:24:17

-2

不,您不能在運行時在PHP中動態更改類。

您可以通過使用常規繼承擴展類實現這一點:

class Fancy extends NotSoFancy 
{ 
    public function whatMakesItFancy() //can also be private/protected of course 
    { 
     //  
    } 
} 

或者你也可以編輯WordPress的源文件。

我寧願繼承的方式。從長遠來看,處理起來要容易得多。

4

適應範圍的2014年更新方式。

public function __call($method, $arguments) { 
    return call_user_func_array(Closure::bind($this->$method, $this, get_called_class()), $arguments); 
} 

如:

class stdObject { 
    public function __call($method, $arguments) { 
     return call_user_func_array(Closure::bind($this->$method, $this, get_called_class()), $arguments); 
    } 
} 

$obj = new stdObject(); 
$obj->test = function() { 
    echo "<pre>" . print_r($this, true) . "</pre>"; 
}; 
$obj->test(); 
+1

這對於任何類名都非常有效。在$ obj-> test中,您還可以執行$ this-> someClassMethod()和$ this-> privateVarName。您還可以在可以訪問類方法和變量的成員函數內部創建函數。 – 2016-11-18 10:32:07