說(shuō)明:TP6的官方文檔很啰嗦,而且給出了若干并不良好的實(shí)踐方式。
先上答案:
1. 假設(shè)有自定義的事件如aaa,在event.php文件中l(wèi)isten數(shù)組里,添加一項(xiàng):鍵名為'aaa',鍵值為一個(gè)一維數(shù)組,里面是若干類名稱如BB::class,CC:;class,DD::class。
2. BB,CC,DD 都有一個(gè)handle方法,在需要執(zhí)行BB,CC,DD中handle方法的地方,寫上Event::trigger('aaa')
----------------------------------------------------------------------------------------------------
再說(shuō)原因:
事件的概念,可以理解為數(shù)組的一個(gè)key,該key對(duì)應(yīng)多個(gè)函數(shù)。類似于['eventName' => ['fun1','fun2']]
監(jiān)聽就是一直“監(jiān)視”某個(gè)事件是否完成(程序是否執(zhí)行到標(biāo)記位置),完成則執(zhí)行若干函數(shù),如上面的fun1和fun2。
觸發(fā),就是使事件變?yōu)橥瓿?執(zhí)行事件上所綁定的函數(shù)(監(jiān)聽器)。
即一個(gè)完整的事件監(jiān)聽流程分為: 定義事件,綁定監(jiān)聽器,觸發(fā)事件三個(gè)部分。
一個(gè)典型的事件,就是瀏覽器的文檔加載完畢。當(dāng)文檔加載完畢后,彈出廣告,歡迎語(yǔ)之類的。
這里的事件是 document.ready,監(jiān)聽器是彈廣告歡迎,觸發(fā)動(dòng)作是瀏覽器完成的,加載完文檔就觸發(fā)。

舉一個(gè)常見的例子:填寫表單,提交表單,注冊(cè)完畢都是標(biāo)記(事件,鉤子), 注冊(cè)完畢后,給新帳號(hào)增加金幣,積分,登錄次數(shù)。

這里的事件,就是注冊(cè)完畢
這里的監(jiān)聽器,就是+金幣,+積分,+次數(shù)三個(gè)功能。
事件觸發(fā)就是,【注冊(cè)完畢】這個(gè)事件發(fā)生了,執(zhí)行上述三個(gè)功能。
上述場(chǎng)景在TP6中的實(shí)現(xiàn)方式是:
1. 定義一個(gè)事件register_ok
2. 將指定的類如AfterRegister綁定到register_ok事件,
綁定方法為:在app\event.php中的listen數(shù)組中添加:
return [
? ? 'bind'? ? =>? ? [
? ? ],
? ? 'listen'? =>? ? [
? ? ? ? // 事件名稱為 register_ok,對(duì)應(yīng)的監(jiān)聽類為AfterRegister
? ? ? ? 'register_ok'? ? =>? ? ['app\listener\AfterRegister::class'],
? ? ],
];
3. 當(dāng)register_ok觸發(fā)時(shí),執(zhí)行AfterRegister中的方法(默認(rèn)執(zhí)行handle方法,在handle中去依次執(zhí)行三個(gè)動(dòng)作)
觸發(fā)方式為:Event::trigger('register_ok',$user); 觸發(fā)函數(shù)是可以傳參的,如這里的$user,對(duì)應(yīng)的AfterRegister中的handle方法,也具有對(duì)應(yīng)的形參
class AfterRegister
{
function handle($user){... ...}
}
那么事件監(jiān)聽的實(shí)現(xiàn)方式,跟傳統(tǒng)的函數(shù)調(diào)用有何優(yōu)勢(shì)?
事件使用場(chǎng)景一:
A,B,C三個(gè)人分別負(fù)責(zé)會(huì)員登錄后增加金幣,增加積分,增加登錄次數(shù)記錄的功能書寫。
傳統(tǒng)寫法:
// 注冊(cè)
。。。
// 注冊(cè)完畢增加金幣積分次數(shù)
addGold();?
addScore();?
addTimes();
很顯然,此時(shí)如果三個(gè)人修改同一段代碼必然導(dǎo)致沖突。
使用事件則可以如下方式完成:
①,約定事件名稱為register_ok,分別綁定三個(gè)監(jiān)聽類(目的是將上例中AfterRegister中的handle方法中+金幣+積分+次數(shù)拆開,分別放到AddGold,AddScore,AddTimes的handle函數(shù)中):
return [
? ? 'bind'? ? =>? ? [
? ? ],
? ? 'listen'? =>? ? [
? ? ? ? //? 給register_ok事件,綁定三個(gè)監(jiān)聽類,分別為AddGold,AddScore,AddTimes
? ? ? ? 'register_ok'? ? =>? ? ['app\listener\AddGold::class','app\listener\AddScore::class','app\listener\AddTimes::class']
? ? ],
];
②,在app\listener中加三個(gè)類,分別為AddGold,AddScore,AddTimes
③,在AddGold的handle方法中寫增加金幣的業(yè)務(wù),AddScore的handle方法中寫增加積分的業(yè)務(wù),AddTimes的handle方法中寫增加次數(shù)的業(yè)務(wù)
④,在注冊(cè)代碼的下方,加入事件觸發(fā),即用一個(gè)Event::trigger('register_ok',$user);取代了原本 addGold(); addScore(); addTimes();這種若干個(gè)函數(shù)的寫法。
至此則完成了,N個(gè)監(jiān)聽類去監(jiān)聽一個(gè)事件的功能?;蛟S有人說(shuō),傳統(tǒng)寫法一樣可以用,三個(gè)人分別實(shí)現(xiàn)addGold(); addScore(); addTimes(); 就可以了,那么看下面這個(gè)場(chǎng)景
事件使用場(chǎng)景二:
某系統(tǒng)會(huì)員注冊(cè)成功后,增加金幣。
過(guò)了幾周,要求增加金幣的同時(shí)增加積分。
又過(guò)了幾周,要求增加金幣和積分的同時(shí)增加登錄次數(shù)。
又過(guò)了幾周,要求只增加金幣和登錄次數(shù),不加積分了。
又過(guò)了幾周,要求注冊(cè)成功后增加金幣和登錄次數(shù)的同時(shí),記錄下會(huì)員的登錄IP。
如果是使用傳統(tǒng)方式,需要對(duì)源代碼進(jìn)行不斷的修改和注釋,事件則方便的多,只追加監(jiān)聽器和修改配置文件event.php,而不必改注冊(cè)部分的業(yè)務(wù)代碼??梢?,事件監(jiān)聽的實(shí)現(xiàn)方式,在頻繁出現(xiàn)業(yè)務(wù)變更的地方,有著傳統(tǒng)方式不能比的優(yōu)勢(shì)。
---------------------------------------------------------------------------------------------------
后記:
1. TP6的文檔中給出了事件類event的定義,實(shí)際中幾乎沒有使用的必要,徒增理解成本。
2. 對(duì)于事件的監(jiān)聽也給出了Event::listen的動(dòng)態(tài)綁定方式,遠(yuǎn)不如在event.php中指定,更為方便和靈活可控。
3. 通常我們理解的綁定是 將監(jiān)聽器綁定到事件,這也是JS中的addEventListener的語(yǔ)義,TP6文檔給出的綁定定義則是,將事件名稱綁定到對(duì)應(yīng)的事件類。
4. 基于以上三點(diǎn),個(gè)人推薦采用 event.php配置文件進(jìn)行監(jiān)聽, 用Event::trigger的方式進(jìn)行觸發(fā)事件,而不要用Event::bind和Event::listen。