2011-12-04 104 views
3

我有以下代碼;什麼應該添加到裝飾類通過method_exists()的檢查?在實際任務中,我無法更改調用method_exists()的功能。
還有什麼想法如何欺騙'get_class_methods()'和'get_class_vars()'?修飾符和方法表達式

class real { 
    function __construct($arg1,$arg2) 
    { 

    } 

    function test() 
    { 
     echo "test output\n"; 
    } 
} 

class decorator 
{ 
    protected $real; 

    function __construct() 
    { 
     eval('$this->real=new real('.implode(',',func_get_args()).');'); 
    } 

    function __call($method,$args) 
    { 
     echo "called $method\n"; 
     $ret=call_user_func_array(array($this->real, $method), $args); 
     return $ret; 
    } 

    public function __isset($name) 
    { 
     echo "isset $name\n"; 
    } 
} 
//-----Can't change below 
$r=new decorator(1,2); 
if (!method_exists($r,'test')) {die ("method 'test' does not exist, Fail :(\n");} 
echo $r->test(); 

任何想法? (我正在考慮通過eval()生成封裝類)

+0

我做了eval()包裝,但希望更好的解決方案 –

回答

1

這個答案是非常簡單的:

讓裝飾類擴展現實類

<?php 
class real { 
    function __construct() { 
     var_dump(func_get_args()); 
    } 
    protected function test(){ 
     echo "test output\n"; 
    } 
} 
class decorator extends real{ 
    function __construct(){ 
     parent::__construct(func_get_args()); 
    } 

    function __call($method,$args){ 
     echo "called $method\n"; 
     return call_user_func_array(array('parent', $method), $args); 
    } 

    public function __isset($name) { 
     echo "isset $name\n"; 
    } 
} 
//-----Can't change below 
$r = new decorator(1,2); 
if(!method_exists($r,'test')) {die ("method 'test' does not exist, Fail :(\n");} 
echo $r->test(); 

這是一個更好的設計,並it works

爲了更好地解決檢查專有編碼程序的根本問題,我還建議使用XDebug's execution_trace

+0

函數__call(),不會在每次調用時調用, –

+0

它會在'real'和'decorator'的每個非公共成員函數上調用。 – nickb

+0

是的,看起來像,順便說一句在你的示例參數沒有通過正確, –

0

__construct()的簽名是void __construct ([ mixed $args [, $... ]])

換句話說,__construct()只返回對象的一個​​實例。

我覺得你在factory method pattern和裝飾者模式之間混淆不清。

1

首先,__construct永遠不會返回。

其次,是一個很好的/真正的裝飾圖案,decorator類必須裝點real物體或其他real擴展的對象,所以你不應該在構造方法中實例化對象。一裝飾圖案例子可以幫助你理解:

$coffee = new Coffee(); 
$coffe_extra_sugar = new Sugar($coffee); // Here you put more sugar 
$coffe_extra_extra_sugar = new Sugar($coffe_extra_sugar); // Here you put more sugar! 

class NewCoffe extends Coffee{} // Now a new coffee 

$ncoffe = new NewCoffe(); 
$ncoffe_extra_sugar = new Sugar($ncoffe); // Good Decorator! 

第三,你可以創建real類中的方法,誰檢查方法存在:

public function method_exists($method){ 
    return method_exists($this,$method); 
} 

和裝飾創建它太(不要忘了檢查到真正的對象):

public function method_exists($method){ 
    return method_exists($this,$method) || $this->real->method_exists($method); 
} 

現在想和我在一起,如果你所有的裝飾從一個獨特的咖啡裝飾延伸,你不需要定義這個方法我n要在每個裝飾,所以在我的咖啡例如:

class CoffeeDecorator { 

    protected $real; 

    public function __construct($decorated_class){ 
     $this->real = $decorated_class; 
    } 

    public function method_exists($method){ 
     return method_exists($this,$method) || $this->real->method_exists($method); 
    } 

    function __call($method,$args){ 
      echo "called $method\n"; 
      $ret=call_user_func_array(array($this->real, $method), $args); 
      return $ret; 
    } 

} 

// Now create some coffe decorators 
class Sugar extends CoffeeDecorator{ 
    // Methods for sugar decorator 
} 
+0

但如果在實際方法中定義的代碼調用函數__call()不會被執行,真正的任務是打包專用軟件模塊來調試那些軟件在模塊上做。另外爲什麼class_method_exist()會調用CoffeDecorator-> method_exists()?它被記錄在某處? –

+0

只對未聲明爲decorator(糖)類的方法執行__call,所有真實類的專有方法將在您的if(!method_exists($ r,'test'))中調用... ''你必須改成'if(!$ r-> method_exists('test'))'...... –

+0

我知道何時執行__call(),因爲我放在代碼中 - 我們不能改變調用class_method_exists() –

0

使用override_function

編譯PHP apd
一旦你有這個準備,
你可以很容易地覆蓋內置函數method_exist到is_callable

的method_exist只需更改爲 is_callable: -

$methodVariable = array($r, 'test'); 
var_dump(is_callable($methodVariable, true, $callable_name)); 
echo $callable_name, "\n"; 

輸出: -

bool(true) 
decorator::test 

什麼是is_callable?

驗證變量的內容是否可以作爲函數調用。這可以檢查一個簡單的變量是否包含有效函數的名稱,或者數組是否包含正確編碼的對象和函數名稱。

要添加,method_exist只是檢查,
你的情況 ,方法是 NEVER實際聲明,
而is_callable檢查方法可以被調用,
與__call,這是返回true。

+0

調用在專有編碼軟件中使用method_exist(記錄不完善),我需要攔截所有對模塊類的調用並記錄它,以便更多地理解邏輯,所以我不能將method_exists()更改爲其他函數。 –

+0

抱歉,理解力差。總之,**沒有**,我想你想抓住所有的動態調用任何方法?但是當在對象上下文中調用不可訪問的方法時會觸發'__call'。所以,就像雞或雞蛋問題。其餘的答案建議硬編碼所有類型的方法,我認爲你真的在追求什麼。 – ajreal