最近在開發一個PHP系統,為了提高系統的擴充性,我想在系統中加入類似Javascript的事件處理機制,例如:我想在一篇新聞被加入以後,我想記錄日誌,用類似Javascript的程式碼,應該是這樣寫的:
function fnCallBack( $news ) { //将$news的信息记录到日志中 writeLog( $news->getTitle().' has been added successfully!'); } $newsEventManager->addEventListener( 'add' , fnCallBack );
其中,fnCallBack函數是回呼函數,addEventListener表示監聽newsEventManager的add事件。當一篇news被add以後,系統就會呼叫fnCallBack函數,從而完成writeLog的動作。
但是,PHP中的函數傳遞方法和Javascript有很大的不同。在Javascript中,函數也是對象,它可以很方便的當作參數傳遞,但是PHP不行。
$newsEventManager->addEventListener( 'add' , fnCallBack );
上面這行程式碼中的fnCallBack,看起來好像是那個函數的句柄,但實質上它是一個字串,並不是我們所要的函數。
為了實作我們的事件模型,有必要研究一下PHP的回呼函數的實作方法。
1. 全域函數的回呼
這裡的全域函數的意思,是直接使用function定義的函數,它不包含在任何物件或類別之中。請看下面的範例
範例程式碼:
function fnCallBack( $msg1 , $msg2 ) { echo 'msg1:'.$msg1; echo "<br />\n"; echo 'msg2:'.$msg2; } $fnName = "fnCallBack"; $params = array( 'hello' , 'world' ); call_user_func_array( $fnName , $params );
程式碼說明:
這裡使用了PHP內建的函數call_user_func_array來進行呼叫。 call_user_func_array有兩個參數,第1個參數是一個字串,表示要呼叫的函數名,第2個參數是數組,表示參數列表,依照順序依序會傳遞給要呼叫的函數。
2. 類別的靜態方法的回呼
如果我們要回呼的方法,是一個類別的靜態方法,那該怎麼辦呢?我們依然可以利用PHP內建的call_user_func_array方法來進行調用,請看範例:
範例程式碼:
class MyClass { public static function fnCallBack( $msg1 , $msg2 ) { echo 'msg1:'.$msg1; echo "<br />\n"; echo 'msg2:'.$msg2; } } $className = 'MyClass'; $fnName = "fnCallBack"; $params = array( 'hello' , 'world' ); call_user_func_array( array( $className , $fnName ) , $params );
程式碼說明:
這段程式碼和第1種方法的程式碼很相似,我們將類別名稱(MyClass)也當作call_user_func_array的第1個參數傳遞進去,就可以實作類別的靜態方法的回呼了。注意,這時call_user_func_array的第1個參數是一個陣列了,陣列的第1個元素是類別名,第二個元素是要呼叫的函數名
3. 物件的方法的回呼
先用最原始的字串形式的呼叫方法嘗試了一下,如下所示:
class MyClass { private $name = 'abc'; public function fnCallBack( $msg1 = 'default msg1' , $msg2 = 'default msg2' ) { echo 'object name:'.$this->name; echo "<br />\n"; echo 'msg1:'.$msg1; echo "<br />\n"; echo 'msg2:'.$msg2; } } $myobj = new MyClass(); $fnName = "fnCallBack"; $params = array( 'hello' , 'world' ); $myobj->$fnName();
呼叫是成功了,不過如何把參數params傳給這個方法呢,如果把params直接傳進去,那麼它會當作1個參數,要怎麼把params拆開來傳進去呢?
查了一下PHP手冊,找到了create_function函數,這個方法可以用字串來創建一個匿名函數,好,有思路了,可以創建一個匿名的函數,在這個匿名函數中,呼叫我們的回呼函數,並把參數傳進去。
先手動建立一個匿名函數anonymous,在這個函數中,用前面試出來的方法呼叫回呼函數,如下所示:
class MyClass { private $name = 'abc'; public function fnCallBack( $msg1 = 'default msg1' , $msg2 = 'default msg2' ) { echo 'object name:'.$this->name; echo "<br />\n"; echo 'msg1:'.$msg1; echo "<br />\n"; echo 'msg2:'.$msg2; } } $myobj = new MyClass(); $fnName = "fnCallBack"; $params = array( 'hello' , 'world' ); function anonymous() { global $myobj; global $fnName; global $params; $myobj->$fnName( $params[0] , $params[1] ); } anonymous();
然後,我用create_function來創建這個匿名函數,同時,程式碼中的params[0],params[1]應該是動態產生的,程式碼如下:
$strParams = ''; $strCode = 'global $myobj;global $fnName;global $params;$myobj->$fnName('; for ( $i = 0 ; $i < count( $params ) ; $i ++ ) { $strParams .= ( '$params['.$i.']' ); if ( $i != count( $params )-1 ) { $strParams .= ','; } } $strCode = $strCode.$strParams.");"; $anonymous = create_function( '' , $strCode); $anonymous();
這段程式碼可以定義一個匿名函數,並保存在$ anonymous變數中,最後呼叫這個$anonymous,實作了方法的回呼。
以上是php自訂函數的回呼函數用法詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!