2014-06-21 64 views
0

我創建不是很複雜的測試代碼(在PHP 5.5.12測試):可贖回和倒閉

<?php 

class Test 
{ 
    private $cached = null; 

    public function __construct() 
    { 
     $this->cached = []; 
     $this->cached[0] = 12; 
    } 

    function wrap($function, $index) 
    { 
     if (isset($this->cached[$index])) { 
      return $this->cached[$index]; 
     } 

     $result = call_user_func($function); 

     return $result; 
    } 
} 

class B 
{ 
    public function run() 
    { 
     $x = 6; 
     $obj = new Test(); 
     $value = $obj->wrap(
      function() use ($x) { 
       return $this->test($x); 
      }, 
      1 
     ); 
     echo $value."<br />"; 
    } 


    protected function test($x) 
    { 
     echo "I'm running "; 
     return $x * $x; 
    } 
} 

class C extends B 
{ 
    public function run() 
    { 
     $x = 6; 
     $obj = new Test(); 

     $myFunc = function() use ($x) { 
     return $this->test($x); 
     }; 

     $value = $obj->wrap($myFunc, 1); 
     echo $value."<br />"; 
    } 
} 

class D extends B 
{ 
    public function run() 
    { 
     $x = 6; 
     $obj = new Test(); 

     $value = $obj->wrap(array($this, 'test'), 1); 
     echo $value."<br />"; 
    } 
} 


$b = new B(); 
$b->run(); 

$c = new C(); 
$c->run(); 

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

大概有代碼的某些部分,你可以說這是可以做到更好,但主點是關閉功能並可調用。這些類以非常簡單的方式模擬緩存系統。如果數據在緩存中,它將從緩存中返回數據,否則將調用獲取數據的函數(當然,這個緩存系統不起作用,因爲它不必 - 它只是一個示例代碼)。

問題:

1)爲什麼要使用對象$d我得到以下警告時:

call_user_func() expects parameter 1 to be a valid callback, cannot access protected method D::test() 

,並有可能從母公司推出的保護方法?當我將此方法從受保護的方法更改爲公共方法時,它可以毫無問題地啓動。

2)正如您可能注意到的,我想使用一些參數作爲函數,我使用call_user_sync調用。不幸的是,我不知道這些參數,當我呼叫call_user_func,所以在B類和C類我使用閉包,我可以使用/傳遞額外的參數。我有兩個額外的問題連接到這個:

  • 它是關閉是有用的和常用的方式?

  • 是有可能使用對象$d傳遞參數測試方法不使用封閉但不調用call_user_sync但內部D類時?

+0

_is有可能從父母啓動受保護的方法嗎?_這不是你正在做的事情。您不會從父級啓動受保護的方法。你正試圖調用'D'實例內'Test'實例的受保護方法。 – hindmost

+0

你確定嗎?在我的代碼中,我看到我試圖調用'B'類的受保護方法'test'(這是'D'類的父類),當我將此方法更改爲public時,此方法正在啓動 –

+1

您可以使用'array ($ this,'method')'只有在相同的上下文中使用私有/受保護的方法。當你在函數內部創建對象'$ obj'並將回調'數組($ this,'test')'傳遞給這個對象函數時,它會在沒有上下文的情況下傳遞。在'Test :: wrap'函數內部,回調被稱爲'$ objectOfClassD-> test(1)',而不是'$ this-> test(1)'和方法'D :: test()'被保護。當你將'D :: test()'公開時,它可以從任何上下文訪問,並且不會產生警告。 – piotrekkr

回答

1

在執行時注意範圍很重要。您是創建在正確的範圍回調,但你執行回調的另一個對象沒有訪問protected方法(回調GET在class Test不是在class B父母或子女執行。

前一段時間,我在編寫自己的調度程序類時遇到了這個問題,其中一種方法是在調度程序中設置「父級」,並將調度程序作爲回調參數之一傳遞,然後調用「父級」與調度員關聯=== $this,然後知道它已經進入城鎮並且去鎮上

你哈做你自己的訪問檢查,是重點。