2013-05-05 74 views
1

假設這個類代碼:是否可以存儲對象方法的引用?

class Foo { 
    function method() { 
     echo 'works'; 
    } 
} 

有什麼辦法來存儲到Foo實例的method方法的引用?

我只是試驗和擺弄,我的目標是檢查PHP是否允許在每次都沒有寫入$FooInstance->的情況下調用$FooInstance->method()。我知道我可以爲此寫一個函數包裝器,但我更感興趣的是獲取對實例方法的引用。

例如,這種僞代碼理論上存儲$foo->method$method變量:

$foo = new Foo(); 
$method = $foo->method; //Undefined property: Foo::$method 
$method(); 

顯然,作爲method是一個方法,我不()調用它的解釋認爲我在找對於一個財產,因此這是行不通的。

我已閱讀Returning References,但示例僅顯示如何返回對變量的引用,而不是方法。

因此,我已經適應我的代碼存儲在一個變量匿名函數並返回它:

class Foo { 
    function &method() { 
     $fn = function() { 
      echo 'works'; 
     }; 
     return $fn; 
    } 
} 

$foo = new Foo(); 
$method = &$foo->method(); 
$method(); 

這工作,但比較難看。此外,沒有簡單的方法來調用它一次,因爲這似乎需要將返回的函數存儲在變量之前調用它:$foo->method()();($foo->method())();是語法錯誤。

而且,我已經試過的情況下直接將其存儲在一個變量返回的匿名函數,但我得到通知如下:

注意:只有變量引用應參考

返回

這是否意味着返回/存儲對類實例方法的引用是不可能的/不鼓勵或者我忽略了某些東西?


更新:我不介意,如果有必要增加一個getter,我們的目標是剛開的方法的引用。我甚至已經試過:

class Foo { 
    var $fn = function() { 
     echo 'works'; 
    }; 
    function &method() { 
     return $this->fn; 
    } 
} 

但從unexpected 'function' (T_FUNCTION)錯誤我相信PHP明智不允許屬性來存儲功能。

我開始相信,如果不使用醜陋的黑客,我的目標不易實現,如eval()

回答

5

它是。您必須使用一個數組,其中包含兩個值:類實例(如果調用靜態方法,則爲類名的字符串),方法名稱爲字符串。這被記載於Callbacks Man page

一個實例化的對象的方法,作爲含有在索引0處的對象,並在索引方法名1.

演示(Codepad)的陣列被傳遞:

<?php 
class Something { 
    public function abc() { 
     echo 'called'; 
    } 
} 

$some = new Something; 

$meth = array($some, 'abc'); 

$meth(); // 'called' 

注意這也適用與需要回調的內置插件(Codepad):

class Filter { 
    public function doFilter($value) { 
     return $value !== 3; 
    } 
} 

$filter = new Filter; 
$test = array(1,2,3,4,5); 
var_dump(array_filter($test, array($filter, 'doFilter'))); // 'array(1,2,4,5)' 

而對於靜態方法 - 注意'Filter',而不是一類的陣列(Codepad)中第一個元素的一個實例:

class Filter { 
    public static function doFilter($value) { 
     return $value !== 3; 
    } 
} 

$test = array(1,2,3,4,5); 

var_dump(array_filter($test, array('Filter', 'doFilter'))); // 'array(1,2,4,5)' 
// -------- or ----------- 
var_dump(array_filter($test, 'Filter::doFilter')); // As of PHP 5.2.3 
+0

我見過'()'一個字符串變量,但它是我第一次看到一個數組被調用。感謝Man頁面鏈接。 '=]' – 2013-05-05 02:31:58

+0

@FabrícioMatté我已更新添加到文檔頁面的鏈接。它與回調。這是一段時間的慣例,但我認爲它看起來非常醜陋。 – 2013-05-05 02:35:46

+0

如果你稱之爲醜陋,我希望你永遠不必閱讀我的JavaScript代碼片段。 ';''再次感謝您的快速回答。 – 2013-05-05 02:37:48

4

是的,可以。 PHP有一個「可調用的」僞類型,實際上,它只是一個字符串或一個數組。幾個函數(usort想到)接受「回調」類型的參數:實際上,他們只是想要一個函數名稱或一個對象方法對。

這是正確的,字符串是調用:

$fn = "strlen"; 
$fn("string"); // returns 6 

如前所述,它可以使用數組作爲回調了。在這種情況下,第一個元素是一個對象,第二個參數必須是一個方法名稱:

$obj = new Foo(); 
$fn = array($obj, "method"); 
$fn(); // calls $obj->method() 

以前,您必須使用call_user_func打電話給他們,但在最新版本的語法糖有可能直接對變量進行調用。

您可以在"callable" documentation page上閱讀更多信息。

+0

是的,我知道字符串保存函數名稱,但這是我第一次看到數組語法。 +1的詳細答案,我會接受這個,但@PhpMyCoder首先回答。 – 2013-05-05 02:34:55

0

不,據我所知,不可能在PHP中存儲對方法的引用。在數組中存儲對象/類名稱和方法名稱是可行的,但它只是一個沒有任何特殊含義的數組。您可以使用數組,請你,例如玩:

$ref = [new My_Class(), "x"]; 
// all is fine here ... 
$ref(); 
// but this also valid, now the 'reference' points to My_Other_Class::x() 
// do you expect real reference to behave like this? 
$ref[0] = new My_Other_Class(); 
$ref(); 
// this is also valid syntax, but it throws fatal error 
$ref[0] = 1; 
$ref(); 
// let's assume My_Class::y() is a protected method, this won't work outside My_Class 
$ref = [new My_Class(), 'y']; 
$ref(); 
  • 你丟掉語法檢查,由於存儲方法的字符串類型,這是容易出錯。
  • 您無法以這種方式可靠地傳遞對私有或受保護方法的引用(除非您從已經有適當方法訪問的上下文中調用引用)。

我個人更喜歡使用lambda表達式:如果你這樣做從內$my_object它變得不太笨重感謝訪問$this

$ref = function() use($my_object) { $my_object->x(); } 

$ref = function() { $this->x(); } 
  • 這工作與保護/私有方法
  • 語法檢查在IDE中工作(less b UGS)
  • 不幸的是它不太簡潔
相關問題