亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > PHP > 正文

深入解析PHP的Yii框架中的event事件機制

2020-03-22 17:33:35
字體:
來源:轉載
供稿:網友
事件
事件可以將自定義代碼“注入”到現有代碼中的特定執行點。附加自定義代碼到某個事件,當這個事件被觸發時,這些代碼就會自動執行。例如,郵件程序對象成功發出消息時可觸發 messageSent 事件。如想追蹤成功發送的消息,可以附加相應追蹤代碼到messageSent 事件。
Yii 引入了名為 yii/base/Component 的基類以支持事件。如果一個類需要觸發事件就應該繼承 yii/base/Component 或其子類。Yii的event機制
YII的事件機制,是其比較獨特之處,合理使用好事件機制,會使各個組件之間的耦合更為松散,利于團體協作開發。
何時需要使用事件,如何給事件綁定事件處理函數,以及如何觸發事件,與其它語言是有較大的差別的。例如Javascript中,可以使用
$(‘#id').on("click",function() {});方式給DOM元素綁定處理函數,當DOM元素上發生指定的事件(如click)時,將自動執行設定的函數。
但是PHP是服務器端的腳本語言,就不存在自動觸發事件之說,所以和Javascript對比,YII中的事件是需要手動觸發的。一般來說,要實現YII組件的事件機制,需要以下幾步:定義事件名稱,其實就是級組件定義一個on開頭的方法,其中的代碼是固定的,如: html' target='_blank'>public function onBeginRequest($event){ $this- raiseEvent('onBeginRequest',$event);即函數名與事件名是一致的。此步的作用就是將綁定在此事件上的處理函數逐個執行。寫這一系列的播客,算是一個整理,所以我寫細一點,現在把raiseEvent方法的代碼貼出來。
/** * Raises an event. * This method represents the happening of an event. It invokes * all attached handlers for the event. * @param string $name the event name * @param CEvent $event the event parameter * @throws CException if the event is undefined or an event handler is invalid. public function raiseEvent($name,$event){ $name=strtolower($name); //_e這個數組用來存所有事件信息 if(isset($this- _e[$name])) { foreach($this- _e[$name] as $handler) { if(is_string($handler)) call_user_func($handler,$event); elseif(is_callable($handler,true)){ if(is_array($handler)){ // an array: 0 - object, 1 - method name list($object,$method)=$handler; if(is_string($object)) // static method call call_user_func($handler,$event); elseif(method_exists($object,$method)) $object- $method($event); else throw new CException(Yii::t('yii','Event "{class}.{event}" is attached with an invalid handler "{handler}".', array('{class}'= get_class($this), '{event}'= $name, '{handler}'= $handler[1]))); else // PHP 5.3: anonymous function call_user_func($handler,$event); else throw new CException(Yii::t('yii','Event "{class}.{event}" is attached with an invalid handler "{handler}".', array('{class}'= get_class($this), '{event}'= $name, '{handler}'= gettype($handler)))); // stop further handling if param.handled is set true if(($event instanceof CEvent) && $event- handled) return; } elseif(YII_DEBUG && !$this- hasEvent($name)) throw new CException(Yii::t('yii','Event "{class}.{event}" is not defined.', array('{class}'= get_class($this), '{event}'= $name)));事件處理器(Event Handlers)事件處理器是一個PHP 回調函數,當它所附加到的事件被觸發時它就會執行。可以使用以下回調函數之一: 字符串形式指定的 PHP 全局函數,如 'trim' ; 對象名和方法名數組形式指定的對象方法,如 [$object, $method] ; 類名和方法名數組形式指定的靜態類方法,如 [$class, $method] ; 匿名函數,如 function ($event) { ... } 。事件處理器的格式是:function ($event) { // $event 是 yii/base/Event 或其子類的對象通過 $event 參數,事件處理器就獲得了以下有關事件的信息: yii/base/Event::name:事件名 yii/base/Event::sender:調用 trigger() 方法的對象 yii/base/Event::data:附加事件處理器時傳入的數據,默認為空,后文詳述附加事件處理器調用 yii/base/Component::on() 方法來附加處理器到事件上。如:$foo = new Foo;// 處理器是全局函數$foo- on(Foo::EVENT_HELLO, 'function_name');// 處理器是對象方法$foo- on(Foo::EVENT_HELLO, [$object, 'methodName']);// 處理器是靜態類方法$foo- on(Foo::EVENT_HELLO, ['app/components/Bar', 'methodName']);// 處理器是匿名函數$foo- on(Foo::EVENT_HELLO, function ($event) { //事件處理邏輯附加事件處理器時可以提供額外數據作為 yii/base/Component::on() 方法的第三個參數。數據在事件被觸發和處理器被調用時能被處理器使用。如:// 當事件被觸發時以下代碼顯示 "abc"http:// 因為 $event- data 包括被傳遞到 "on" 方法的數據$foo- on(Foo::EVENT_HELLO, function ($event) { echo $event- data;}, 'abc');事件處理器順序可以附加一個或多個處理器到一個事件。當事件被觸發,已附加的處理器將按附加次序依次調用。如果某個處理器需要停止其后的處理器調用,可以設置 $event 參數的 [yii/base/Event::handled]] 屬性為真,如下:$foo- on(Foo::EVENT_HELLO, function ($event) { $event- handled = true;默認新附加的事件處理器排在已存在處理器隊列的最后。因此,這個處理器將在事件被觸發時最后一個調用。在處理器隊列最前面插入新處理器將使該處理器最先調用,可以傳遞第四個參數 $append 為假并調用 yii/base/Component::on() 方法實現:$foo- on(Foo::EVENT_HELLO, function ($event) { // 這個處理器將被插入到處理器隊列的第一位...}, $data, false);
觸發事件事件通過調用 yii/base/Component::trigger() 方法觸發,此方法須傳遞事件名,還可以傳遞一個事件對象,用來傳遞參數到事件處理器。如:namespace app/components;use yii/base/Component;use yii/base/Event;class Foo extends Component const EVENT_HELLO = 'hello'; public function bar() $this- trigger(self::EVENT_HELLO);以上代碼當調用 bar() ,它將觸發名為 hello 的事件。提示:推薦使用類常量來表示事件名。上例中,常量 EVENT_HELLO 用來表示 hello 。這有兩個好處。第一,它可以防止拼寫錯誤并支持 IDE 的自動完成。第二,只要簡單檢查常量聲明就能了解一個類支持哪些事件。
有時想要在觸發事件時同時傳遞一些額外信息到事件處理器。例如,郵件程序要傳遞消息信息到 messageSent 事件的處理器以便處理器了解哪些消息被發送了。為此,可以提供一個事件對象作為 yii/base/Component::trigger() 方法的第二個參數。這個事件對象必須是 yii/base/Event 類或其子類的實例。如:namespace app/components;use yii/base/Component;use yii/base/Event;class MessageEvent extends Event public $message;class Mailer extends Component const EVENT_MESSAGE_SENT = 'messageSent'; public function send($message) // ...發送 $message 的邏輯... $event = new MessageEvent; $event- message = $message; $this- trigger(self::EVENT_MESSAGE_SENT, $event);當 yii/base/Component::trigger() 方法被調用時,它將調用所有附加到命名事件(trigger 方法第一個參數)的事件處理器。移除事件處理器從事件移除處理器,調用 yii/base/Component::off() 方法。如:// 處理器是全局函數$foo- off(Foo::EVENT_HELLO, 'function_name');// 處理器是對象方法$foo- off(Foo::EVENT_HELLO, [$object, 'methodName']);// 處理器是靜態類方法$foo- off(Foo::EVENT_HELLO, ['app/components/Bar', 'methodName']);// 處理器是匿名函數$foo- off(Foo::EVENT_HELLO, $anonymousFunction);注意當匿名函數附加到事件后一般不要嘗試移除匿名函數,除非你在某處存儲了它。以上示例中,假設匿名函數存儲為變量$anonymousFunction 。移除事件的全部處理器,簡單調用 yii/base/Component::off() 即可,不需要第二個參數:$foo- off(Foo::EVENT_HELLO);類級別的事件處理器以上部分,我們敘述了在實例級別如何附加處理器到事件。有時想要一個類的所有實例而不是一個指定的實例都響應一個被觸發的事件,并不是一個個附加事件處理器到每個實例,而是通過調用靜態方法 yii/base/Event::on() 在類級別附加處理器。例如,活動記錄對象要在每次往數據庫新增一條新記錄時觸發一個 yii/db/BaseActiveRecord::EVENT_AFTER_INSERT 事件。要追蹤每個活動記錄對象的新增記錄完成情況,應如下寫代碼:use Yii;use yii/base/Event;use yii/db/ActiveRecord;Event::on(ActiveRecord::className(), ActiveRecord::EVENT_AFTER_INSERT, function ($event) { Yii::trace(get_class($event- sender) . ' is inserted');每當 yii/db/BaseActiveRecord 或其子類的實例觸發 yii/db/BaseActiveRecord::EVENT_AFTER_INSERT 事件時,這個事件處理器都會執行。在這個處理器中,可以通過 $event- sender 獲取觸發事件的對象。當對象觸發事件時,它首先調用實例級別的處理器,然后才會調用類級別處理器??烧{用靜態方法yii/base/Event::trigger()來觸發一個類級別事件。類級別事件不與特定對象相關聯。因此,它只會引起類級別事件處理器的調用。如:use yii/base/Event;Event::on(Foo::className(), Foo::EVENT_HELLO, function ($event) { echo $event- sender; // 顯示 "app/models/Foo"Event::trigger(Foo::className(), Foo::EVENT_HELLO);注意這種情況下 $event- sender 指向觸發事件的類名而不是對象實例。注意:因為類級別的處理器響應類和其子類的所有實例觸發的事件,必須謹慎使用,尤其是底層的基類,如 yii/base/Object。
移除類級別的事件處理器只需調用yii/base/Event::off(),如:// 移除 $handlerEvent::off(Foo::className(), Foo::EVENT_HELLO, $handler);// 移除 Foo::EVENT_HELLO 事件的全部處理器Event::off(Foo::className(), Foo::EVENT_HELLO);全局事件所謂全局事件實際上是一個基于以上敘述的事件機制的戲法。它需要一個全局可訪問的單例,如應用實例。事件觸發者不調用其自身的 trigger() 方法,而是調用單例的 trigger() 方法來觸發全局事件。類似地,事件處理器被附加到單例的事件。如:use Yii;use yii/base/Event;use app/components/Foo;Yii::$app- on('bar', function ($event) { echo get_class($event- sender); // 顯示 "app/components/Foo"Yii::$app- trigger('bar', new Event(['sender' = new Foo]));全局事件的一個好處是當附加處理器到一個對象要觸發的事件時,不需要產生該對象。相反,處理器附加和事件觸發都通過單例(如應用實例)完成。然而,因為全局事件的命名空間由各方共享,應合理命名全局事件,如引入一些命名空間(例:"frontend.mail.sent", "backend.mail.sent")。給組件對象綁定事件處理函數
$component- attachEventHandler($name, $handler);$component- onBeginRequest = $handler ;yii支持一個事件綁定多個回調函數,上述的兩個方法都會在已有的事件上增加新的回調函數,而不會覆蓋已有回調函數。
$handler即是一個PHP回調函數,關于回調函數的形式,本文的最后會附帶說明。如CLogRouter組件的init事件中,有以下代碼:
Yii::app()- attachEventHandler('onEndRequest',array($this,'processLogs'));這就是給CApplication對象的onEndRequest綁定了CLogRouter::processLogs()回調函數。而CApplication組件確實存在名為onEndRequest的方法(即onEndRequest事件),它之中的代碼就是激活了相應的回調函數,即CLogRouter::processLogs()方法。所以從這里可以得出,日志的記錄其實是發生在CApplication組件的正常退出時。在需要觸發事件的時候,直接激活組件的事件,即調用事件即可,如:比如CApplication組件的run方法中:if($this- hasEventHandler('onBeginRequest')) $this- onBeginRequest(new CEvent($this));這樣即觸發了事件處理函數。如果沒有第一行的判斷,那么在調試模式下(YII_DEBUG常量被定義為true),會拋出異常,而在非調試模式下(YII_DEBUG常量定義為false或沒有定義YII_DEBUG常量),則不會產生任何異常。
回調函數的形式:普通全局函數(內置的或用戶自定義的)call_user_func(‘print', $str);類的靜態方法,使用數組形式傳遞call_user_func(array(‘className', ‘print'), $str );對象方法,使用數組形式傳遞$obj = new className();call_user_func(array($obj, ‘print'), $str );匿名方法,類似javascript的匿名函數call_user_func(function($i){echo $i++;},4);或使用以下形式:
$s = function($i) { echo $i++;call_user_func($s,4);總結關于Yii的事件機制其實就是提供了一種用于解耦的方式,在需要調用event的地方之前,只要你提供了事件的實現并注冊在之后的地方需要的時候即可調用。PHP教程

鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久久99免费视频| 日本一区二区三区四区视频| 久久99精品视频一区97| 亚洲第一精品福利| 在线视频欧美日韩| 中文字幕日韩欧美在线视频| 51精品国产黑色丝袜高跟鞋| 欧美—级高清免费播放| 亚洲欧美日韩一区在线| 亚洲r级在线观看| 国产精品爽爽ⅴa在线观看| 黄色成人av在线| 欧美黄色性视频| 深夜精品寂寞黄网站在线观看| 9.1国产丝袜在线观看| 91精品啪在线观看麻豆免费| 亚洲人成免费电影| 欧美福利视频在线观看| 亚洲免费视频网站| 久久视频在线看| 国产成人激情视频| 九九九热精品免费视频观看网站| 亚洲一区二区三区在线视频| 亚洲free性xxxx护士hd| 成人综合国产精品| 精品福利一区二区| 国产午夜精品免费一区二区三区| 欧美成人午夜激情在线| 国产专区欧美专区| 欧美日韩免费网站| 欧美日韩中国免费专区在线看| 国产精品亚洲视频在线观看| 成人免费淫片视频软件| 中文字幕视频一区二区在线有码| 欧美日韩亚洲网| 北条麻妃一区二区三区中文字幕| 国产精品成久久久久三级| 中文字幕久久久av一区| 亚洲人成电影在线播放| 成人性生交大片免费看视频直播| 久久精品人人做人人爽| 国产精品午夜一区二区欲梦| 一区二区欧美激情| 久久久久久久久久久国产| 91国在线精品国内播放| 国产日韩欧美自拍| 亚洲国产免费av| 亚洲欧美第一页| 欧美日韩亚洲91| 日韩欧美成人免费视频| 精品视频在线播放色网色视频| 91免费视频国产| 亚洲肉体裸体xxxx137| 久久精品2019中文字幕| 日本一区二三区好的精华液| 亚洲成人a级网| 性色av一区二区三区在线观看| 中文字幕自拍vr一区二区三区| 久久久视频免费观看| 高清在线视频日韩欧美| 亚洲第一综合天堂另类专| 97视频在线观看网址| 国产做受69高潮| 亚洲丝袜在线视频| 免费不卡在线观看av| 日韩欧美黄色动漫| 国产小视频91| 精品国产成人在线| 国产精品成人久久久久| 日韩亚洲国产中文字幕| 日本三级久久久| 一本色道久久综合狠狠躁篇的优点| 日韩亚洲欧美成人| 欧美日韩综合视频网址| 欧美—级高清免费播放| 国产精品爽黄69| 日韩电影在线观看免费| 成人久久久久久| 欧美亚洲成人网| 日韩动漫免费观看电视剧高清| 欧美中文在线视频| 久久久91精品国产一区不卡| 91亚洲午夜在线| xxxx欧美18另类的高清| 欧美激情videoshd| 最近2019年中文视频免费在线观看| 久久久国产精品一区| 日韩视频免费在线观看| 亚洲欧美另类自拍| 国产亚洲精品综合一区91| 成人精品视频久久久久| 久精品免费视频| 成人黄色免费在线观看| 最近2019年日本中文免费字幕| 亚洲精品99999| 欧美一乱一性一交一视频| 欧美极品美女电影一区| 亚洲午夜av久久乱码| 91精品国产自产在线| 色www亚洲国产张柏芝| 欧美亚州一区二区三区| 亚洲美女在线看| 狠狠久久亚洲欧美专区| 国产一区二区黑人欧美xxxx| 操人视频在线观看欧美| 久久夜精品香蕉| 国产成人精品免高潮费视频| 亚洲国产精品va在线看黑人| 蜜臀久久99精品久久久久久宅男| 国产精品自产拍在线观| 成人自拍性视频| 精品国产一区二区三区久久狼5月| 久久视频在线视频| 亚洲女人初尝黑人巨大| 国产精品久久久久久一区二区| 亚洲欧美日韩图片| 欧美日韩国产黄| 欧美成人第一页| 欧美在线播放视频| 久久香蕉频线观| 亚洲欧美国产精品va在线观看| 97超视频免费观看| 久久伊人精品天天| 亚洲精品欧美日韩| 亚洲国产免费av| 精品亚洲一区二区三区四区五区| 国产精品高潮粉嫩av| 亚洲精品视频免费在线观看| 国产精品99久久99久久久二8| 中文字幕免费国产精品| 国产www精品| 成人在线中文字幕| 国产精品久久久久久久久久99| 九色成人免费视频| 2019中文字幕在线免费观看| 国产精品美女av| 8090成年在线看片午夜| 国产香蕉精品视频一区二区三区| 国产精品亚洲美女av网站| 色黄久久久久久| 久久国产色av| 欧美专区国产专区| 69国产精品成人在线播放| 成人有码视频在线播放| 亚洲二区中文字幕| 亚洲一区亚洲二区亚洲三区| 亚洲精品91美女久久久久久久| 久久天天躁夜夜躁狠狠躁2022| 亚洲欧洲国产伦综合| 国产精品久在线观看| 精品中文字幕在线2019| 亚洲女人天堂av| 欧美香蕉大胸在线视频观看| 亚洲最大在线视频| 国产精品扒开腿做爽爽爽的视频| 92看片淫黄大片看国产片| 久久精品视频网站| 亚洲视频自拍偷拍| 日韩成人在线免费观看| 青草青草久热精品视频在线观看| 一区二区三区视频免费在线观看| 亚洲最大的av网站| 欧美精品aaa| 欧美福利视频网站|