我這是抄的html
感謝面試
http://www.javashuo.com/article/p-fqkhziep-cm.html數組
全局函數的回調
這裏的全局函數的意思,是直接使用function定義的函數,它不包含在任何對象或類之中。請看下面的例子
示例代碼函數
$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個參數是一個數組,表示參數列表,按照順序依次會傳遞給要調用的函數。
效果以下:

類的靜態方法的回調
若是咱們要回調的方法,是一個類的靜態方法,那怎麼辦呢?咱們依然能夠利用PHP內置的call_user_func_array方法來進行調用,請看示例:
示例代碼:
this
{

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個元素是類名,第二個元素是要調用的函數名
運行結果:

(其實和第1種方法的結果是同樣的 ^_^ )
繼續研究
若是我用這種方法調用一個類的非靜態方法(也就是把static去掉),會出現什麼結果呢?請看下面代碼.net
{

public 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 );
運行結果

和前面的結果仍是同樣的。。。
如今我爲這個類添加一點屬性,並在方法中引用
設計
{

private $name = 'abc';

public function fnCallBack( $msg1 , $msg2 )

{

echo 'object name:'.$this->name;

echo "<br />\n";

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 );
運行結果

出現解析錯誤,提示$this沒有在對象環境下出現,說明這個方法不能用類來調用,而是要用對象來調用。那咱們就修改一下代碼,建立一個對象:htm
{

public function fnCallBack( $msg1 , $msg2 )

{

echo 'msg1:'.$msg1;

echo "<br />\n";

echo 'msg2:'.$msg2;

}

}

$myobj = new MyClass();

$className = 'myobj';

$fnName = "fnCallBack";

$params = array( 'hello' , 'world' );

call_user_func_array( array( $className , $fnName ) , $params );
運行結果:

提示call_user_func_array的第1個參數非法,也就是說,調用失敗。看來咱們不能用call_user_func_array方法來回調一個對象的方法了,那麼如何實現對象方法的回調的?
對象的方法的回調
我先用最原始的字符串形式的調用方法嘗試了一下,以下所示:對象
{

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,在這個函數中,用前面試出來的方法調用回調函數,以下所示:
blog
{

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();
成功了,能夠看到,對象的屬性name也輸出來了

而後,我用create_function來建立這個匿名函數,同時,代碼中的params[0],params[1]應該是動態生成的,代碼以下:
= '';

$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中的3種常見的函數類型(全局函數,類靜態函數,對象的方法)均可以回調了,能夠實現文章一開始說的事件模型了 :)
事件模型模仿Firefox的Javascript實現,有3個方法,分別是

addEventListener:註冊一個事件上的響應回調函數

removeEventListener:刪除一個事件上的響應回調函數

fire:觸發一個事件,也就是循環調用全部響應這個事件的回調函數
不過,因爲第二、第3種方法須要傳遞上下文(也就是類名和對象名),因此addEventListener和removeEventListener應該有3個參數,我是這樣設計的:
$evtName , $handler , $scope = null )
第1個參數表示事件名,字符串類型
第2個參數表示回調函數名,字符串類型
第3個參數$scope是上下文環境,一共有3種類型,null表示傳入的handler函數是一個全局函數,字符串類型表示傳入的handler函數是scope類的靜態函數,對象類型表示傳入的scope是一個對象,handler函數是對象的一個方法。
$evtName , $params = null )
這個方法內,會讀取出全部響應evtName的handler,而後判斷它對應的scope,若是是null,則用本文第1種方法回調,若是是字符串,則 用本文第2種方法回調,若是是對象,則用本文第3種方法回調。這樣,一個PHP的事件模型就能夠實現了,並且能夠將回調函數放在某個對象中。