事件與服務容器

pardon110發表於2019-08-05

理論突破,往往產生實踐的創新。反之實踐不甚其解,通常是沒有掌握好理論。Symfony事件系統,涉及到派遣器(事件觸發),訂閱器(事件收集),事件物件(資料附加),監聽器(事件執行),事件傳播,事件佇列優先順序,以及程式元件間的通訊

服務容器

每一個服務都被存放於一個特殊的名為 service container(服務容器)之中 容器把物件的組織方式中心化

  • 取得並使用服務
    • 在控制器中藉助“服務的類名或介面名”, 對 action 的引數進行 type-hinting 以“請求”容器中的服務
    • 可以使用唯一的 "Service ID" 來直接訪問服務, 繼承 Controller 類時內部可直接從容器中取出服務

事件派遣

Symfony 自身提供的內部事件,被定義在 KernelEvents 類中 在 sf 程式執行期間,大量的事件通知會被觸發,程式可監聽這些通知,並執行任意程式碼作為響應

  • 事件監聽器
    • 通常由事件類和監聽介面組成
    • 接收事件物件引數,事件物件持有派遣器自身引用,該引用例項可決定事件能否繼續傳播
    • 事件監聽器優先順序,Symfony的內部監聽,其優先順序範圍是-255到255,預設值為0,順序執行
  • 監聽器模式
    • 監聽者模式是基於:註冊-回撥的事件/訊息通知處理模式,就是被監控者將訊息通知給所有監控者
  • 事件派遣器
    • 事件觸發呼叫者,事件源
    • 事件類註冊成服務,可命名 tags
    • 一個單一的事件派遣器建立之後,它要維護全部相關監聽器的“登記”
    • 當事件通過 dispatcher 被派遣時,所有已註冊的監聽器會接到通知
    • 核心通知 dispatcher 物件派遣事件,派遣器通知事件的全部監聽器,監聽器執行
  • 事件訂閱
    • 訂閱器始終明確知道正在監聽的事件
    • 定義了一個或多個方法,用於監聽一個或多個事件
  • 監聽 VS 訂閱
    • 訂閱器易於複用 與事件有關的內容存在於類中,而不是存在於服務定義中,故 sf 內部使用訂閱器
    • 監聽器更靈活,因 bundles 可以有條件地開啟或關閉它們,基於配置檔案中的某些“選項值”

EventDispatcher元件

  • 作用 使元件之間“通過派遣事件和監聽事件”進行互相通訊
  • 應用背景
    • 需要在專案中提供一個外掛系統
    • EventDispatcher 元件以一種簡單高效的方式,實現了 Mediator 設計模式
      • 中介者定義一個介面用於與各同事物件通訊
      • 每一個同事物件在需與其他同事通訊時,與它的中介者通訊
      • 使控制集中化,減少了子類的生成,將各個同事類解耦,協議多向
      • 可以使用 Observer 模式與 Mediator 通訊
    • 事件
      • 當一個事件被派遣時,該事件被多個監聽器來監聽。
      • 一個Event例項將被同時建立,並被傳遞給所有的監聽器
      • Event 物件自身往往包含著被派遣事件的資料
    • 事件名稱和事件物件
      • Event 類 預設包含一個用於停止 event.propagation方法
      • 特定事件的資料,則為一個擁有附加方法來取得或重寫這些資料的特殊子類
    • 連線到監聽器
      • 欲利用已有的事件,需要訪問派遣器下的監聽器
      • 派遣器的addListener()方法被呼叫時,可以把任何一個有效的PHP回撥(callable)關聯到那個事件
        • 同 yii2 一樣, 監聽器addListener()方法有三個引數
        • 事件名稱(字串),監聽器需要監聽到它
        • 一個PHP回撥,將在特定的事件被派遣時被執行
        • 一個可選的整數優先順序(愈高則愈重要,該監聽將被愈早地觸發)
      • 一旦監聽被註冊到派遣器,它就等待著事件被通知(到自己)
      • 在服務容器中註冊事件監聽
        • 支援把事件派遣器註冊成服務
        • 支援把監聽器註冊成服務
        • 支援把訂閱器註冊成服務
    • 派遣Event
      • dispatch() 方法可以通知給定事件的全部監聽
        • 要派遣的事件名稱,以及用於傳給每個監聽的Event例項
      • 事件派遣器永遠返回被派遣的事件物件
    • 使用事件訂閱器
      • 監聽事件的常規方式就是去註冊一個監聽器給事件派遣器
      • 或通過event subscriber(訂閱器), 向派遣器精確通報它要訂閱哪些事件
        • 除了它自己告訴派遣器“要監聽哪些事件”之外,也需要將該訂閱器註冊給派遣器
    • 停止Event Flow/Propagation
      • 原因 在某些場合,一個監聽在作動時,防止其他監聽被呼叫是有意義
        • 換言之,監聽器必須能夠告訴派遣器,停止向後續的監聽進行關於此事件的全部傳播
      • EventDispatcher Aware 的事件和監聽
        • EventDispatcher 始終向監聽器傳遞被派遣的事件、事件名和一個對派遣器自身的引用
  • 其他派遣器
    • The Container Aware Event Dispatcher
    • The Immutable Event Dispatcher
    • The Traceable Event Dispatcher(由HttpKernel元件提供)

相關文章