1. 程式人生 > 實用技巧 >讓你深刻了解yii2的九個概念

讓你深刻了解yii2的九個概念

與 laravel 相較,Yii2 將配置(依賴關係定義)外化,用行為(更類似於 python 中的織入)類,彌補Trait的一些不足,好處是可以動態擴充套件動作。至於事件處理則大同小異,有趣的是在命名上,yii2 借用了jquery事件系統的那一套,on,off,trigger。當然也相同之處,比如應用都是建立在容器之上。相比其它的面向領域,面向介面程式設計,Yii2 使用模組,來分層,分中心小應用,細化大架構。而getter/setter,及過濾器,java 痕跡太明顯。

元件 Component

  • Yii 應用的主要基石。是yii\base\Component類或其子類的例項
    • 主要由 屬性(Property),事件(Event),行為(Behavior)三個功能組成
    • 比常規的物件(Object)稍微重量級,要使用額外的記憶體和 CPU 時間來處理 事件 和 行為
    • 不需要使用事件和行為時,繼承yii\base\Object, 支援屬性(Property)功能
  • 重寫 Component 或 Object
    • 永遠在重寫的構造方法結尾處呼叫一下父類的構造方法
    • 傳入 $config 作為構造器方法最後一個引數,由父構造方呼叫,在應用配置之前初始化
    • 若重寫了 BaseObject::init () 方法,確保在 init 方法的開頭處呼叫了父類的 init 方法
  • 元件例項化 2 種方式
    • 例項化元件類,new 元件類, 元件普通引數 + 元件配置屬性引數
    • 通過\Yii::createObject
      靜態方法,建立元件例項
      • 第一個陣列引數 class 關聯元件類名,後續關聯元素依次為元件例項屬性及值
      • 第二陣列引數 元件的普通引數

Yii::createObject()基於依賴注入容器實現

  • yii\base\BaseObject類執行時的生命週期
    • 構造方法內的預初始化過程
    • 通過 $config 配置物件
    • 在 init () 方法內進行初始化後的收尾工作
    • 物件方法呼叫,上述步驟皆在物件的構造方法內完成,即獲得例項就已經初始化,可供使用

屬性 Property

  • Yii引入yii\base\Object的基類, 支援基於類內的gettersetter(讀取器和設定器)方法來定義屬性
  • getter 和 setter 定義屬性規則和限制
    • 這類屬性的名字是不區分大小寫,源於 PHP 方法名是不區分大小寫
    • 若此類屬性名和類成員變數相同,以後者為準
    • 該類屬性不支援可見性(訪問限制)
    • 這類屬性的 getter 和 setter 方法只能定義為非靜態的
    • 對不確定有無魔術方法(getter 或 setter的屬性正常呼叫property_exists()將不會生效
      • 若真有此需求,應用canGetProperty()canSetProperty()

事件 Events

  • 事件可以將自定義程式碼 “注入” 到現有程式碼中的特定執行點

    • 附加自定義程式碼到某個事件,當這個事件被觸發時,這些程式碼就會自動執行
  • 事件處理器Event Handlers

    • 事件處理器是一個 PHP 回撥函式,也可以是一個可呼叫物件
    • 字串形式指定的 PHP 全域性函式 ,如'trim'
    • 物件名和方法名陣列形式指定的物件方法,[$object, $method]
    • 類名和方法名陣列形式指定的靜態類方法,如[$class, $method]
    • 匿名函式,如function ($event) { ... }
  • 事件物件 $event

    • event name:事件名
    • event sender:呼叫 trigger () 方法的物件
    • custom data附加事件處理器時傳入的資料,預設為空
  • 附加事件處理器

    • 呼叫元件類的 on 方法,諸如 \yii\base\Component::on ()
    • public void on ( $name, $handler, $data = null, $append = true )
  • 事件處理器順序(Event Handler Order)

    • 當事件被觸發,已附加的處理器將按附加次序依次呼叫
    • 若需要停止同一事件的後續處理器的呼叫,可設定 event 引數的yii\base\Event::event引數的‘yii\base\Event::handled屬性為真
    • 第四個引數 $append 為假時,可在處理器佇列最前面插入新處理器
  • 觸發事件(Triggering Events)

    • 事件通過呼叫yii\base\Component::trigger()方法觸發
      • public void trigger ( $name, yii\base\Event $event = null )
    • 推薦使用類常量來表示事件名,事件物件必須是yii\base\Event類或其子類的例項
  • 移除事件處理器(Detaching Event Handlers)

    • public boolean off ( $name, $handler = null )
  • 類級別的事件處理器

    • 應用場景 想要一個類的所有例項都響應一個被觸發的事件
    • 呼叫靜態方法yii\base\Event::on()在類級別附加處理器
      • 在事件處理器內,通過 $event->sender 獲取觸發事件的物件
      • 當物件觸發事件時,它首先呼叫例項級別的處理器,然後才會呼叫類級別處理器
    • 靜態方法 yii\base\Event::trigger () 來觸發一個類級別事件,移除用 off
    • 移除簽名public static boolean off ( $class, $name, $handler = null )
  • 介面事件

    • 呼叫Event::on()並將介面類名作為第一個引數
    • 可在實現介面事件類中觸發這個事件,但不能讓所有實現這個介面的類都觸發事件
  • 全域性事件

    • 需要一個全域性可訪問的單例,如應用例項
    • 事件觸發者不呼叫其自身的 trigger () 方法,而是呼叫單例的 trigger () 方法來觸發全域性事件
    • 優點 是當附加處理器到一個物件要觸發的事件時, 不需要產生該物件
  • 萬用字元事件 Wildcard Events

    • foo.event.* , 萬用字元模式支援例項 或類級別的事件

行為

  • 行為是yii\base\Behavior或其子類的例項,也稱為 mixins, 類似於原生的 Trait

    • 作用 無須改變類繼承關係即可增強一個已有的 元件 類功能
    • 當行為附加到元件後,它將 “注入” 它的方法和屬性到元件
    • 行為通過元件能響應被觸發的事件,從而自定義或調整元件正常執行的程式碼
  • 處理事件

    • 讓行為響應對應元件的事件觸發, 應覆寫yii\base\Behavior::events()方法
      • 行為的 events () 方法返回事件列表和相應的處理器,指定事件處理器格式如下
        • 指向行為類的方法名的字串
        • 物件或類名和方法名的陣列,如 [$object, ‘methodName’];
        • 匿名方法
  • 附加行為

    • 靜態附加行為
      • 覆寫行為要附加的元件類的 behaviors () 方法即可
      • behaviors () 方法返回行為配置列表,每個行為配置可以是行為類名也可以是配置陣列
      • 過指定行為配置陣列相應的鍵可以給行為關聯一個名稱,這種行為稱為命名行為,反之匿名行為或命名行為
    • 動態附加行為
      • 在對應元件裡呼叫yii\base\Component::attachBehavior()方法
      • yii\base\Component::attachBehaviors()方法一次附加多個行為
        • public void attachBehaviors (array $behaviors )
      • 通過配置附加行為
        • [‘as myBehavior2’ => MyBehavior::className()]
  • 使用行為

    • 必須先將為附加到 component 類或其子類元件,然後可通過訪問元件訪問行為的公共成員變數
    • 若兩個行為都定義了一樣的屬性或方法,並且它們都附加到同一個元件,先附加者有優先權
    • 附加行為到元件時的命名行為,可以使用這個名稱來訪問行為物件,$component->getBehavior('myBehavior');
    • 獲取附加到這個元件的所有行為getBehaviors()
  • 移除行為

    • 可以呼叫yii\base\Component::detachBehavior()方法用行為相關聯的名字實現
  • Yii2 內建行為類

    • yii\behaviors\TimestampBehavior在 Active Record 儲存時自動更新它的時間戳屬性
    • yii\behaviors\BlameableBehavior使用當前使用者 ID 自動填充指定的屬性
    • yii\behaviors\SluggableBehavior自動填充指定的屬性,其值可以在 URL 中用作 slug
    • yii\behaviors\AttributeBehavior在發生特定事件時自動為 ActiveRecord 物件的一個或多個屬性 指定一個指定的值
    • yii2tech\ar\softdelete\SoftDeleteBehavior提供軟刪除和軟恢復 ActiveRecord 的 方法
    • yii2tech\ar\position\PositionBehavior允許通過提供重新排序方法來 管理整數字段中的記錄順序
  • 行為 VS Traits

    • 都將自己的屬性和方法 “注入” 到主類中,二者類似互補類而非替代類
    • 行為類優點
      • 行為類像普通類支援繼承
      • 行為無須修改元件類就可動態附加到元件或移除
      • 行為是可配置的,而 traits 則不可行
      • 行為可以通過響應事件來定製元件的程式碼執行
    • traits 的原因
      • Traits 比行為更有效,因為行為是既需要時間又需要記憶體的物件
    • 名稱衝突解決方案
      • 當附屬於同一組件的不同行為之間可能存在名稱衝突時, 通過優先考慮附加到該元件的行為
      • 不同 traits 引起的名稱衝突需要通過 重新命名受影響的屬性或方法進行手動解決

配置 Configurations

  • 概述

    • 在建立新物件和初始化已存在物件時使用配置
    • 配置通常包含被建立物件的類名和一組將要賦值給物件 屬性的初始值
    • 亦可包含一組將被附加到物件事件上的控制代碼,和一組將被附加到物件上的行為
  • 使用

    • Yii::createObject () 方法接受一個配置陣列並根據陣列中指定的類名建立物件
    • 對於已存在的物件,可以使用Yii::configure()方法根據配置去初始化其屬性
      • Yii::configure($object, $config)
      • 注若配置一個已存在的物件,那麼配置陣列中不應該包含指定類名的 class 元素
  • 配置的格式

    • class元素指定了將要建立的物件的完全限定類名
    • propertyName元素指定了物件屬性的初始值,鍵名是屬性名,值是該屬性對應的初始值
      • 只有公共成員變數以及通過 getter/setter 定義的 屬性可以被配置
    • on eventName元素指定了附加到物件事件上的控制代碼,陣列的鍵名由 on 字首加事件名組成
    • as behaviorName元素指定了附加到物件的行為,值表示建立行為的配置資訊
  • 應用的配置

    • application 類擁有很多可配置的屬性和事件
    • components 屬性可以接收配置陣列並通過應用註冊為元件
    • yii2.0.11+ 系統配置支援使用 container 屬性來配置依賴注入容器
  • 小部件的配置

    • yii\base\Widget::widget()yii\base\Widget::begin()方法都可以用來建立小部件
    • 通過用配置來自定義其屬性,注意 給出類名的情況下,配置陣列不需要再包含 class 鍵
  • 預設配置

    • Yii::createObject()方法基於依賴注入容器實現
    • 使用Yii::creatObject()建立物件時,可以附加一系列預設配置到指定類的任何例項
    • 預設配置可以在入口指令碼 中呼叫Yii::$container->set()來定義

別名

  • 設定與解析
    • 使用Yii::setAlias()來給檔案路徑或 URL 定義別名
    • 呼叫Yii::getAlias()命令來解析根別名到對應的檔案路徑或 URL
  • 應用提供了一個名為 aliases 的可寫屬性, 可在應用配置中設定它
  • 使用別名 Yii 內路徑屬性接受別名
  • Yii2 預定義別名
  • 擴充套件的別名
    • 一個通過 Composer 安裝的 擴充套件 都自動添加了一個別名,定義於引導啟動階段

類的自動載入

  • Yii 自動載入器
    • 每個類都必須置於名稱空間之下
    • 每個類都必須儲存為單獨檔案
    • 要將自定義名稱空間新增到自動載入器,需要使用 Yii::setAlias () 為名稱空間的根目錄定義別名
  • 類對映表
    • 類對映表功能,建立一個從類的名字到類檔案路徑的對映
    • 當自動載入器載入一個檔案時,他首先檢查對映表裡有沒有該類
    • 可以用Yii::$classMap方法向對映表中新增類
  • 其他自動載入器
    • 在其他自動載入器安裝成功之後, 再包含 Yii.php (yii 的自動載入器)
    • 目的使 Yii 成為第一個響應任何類自動載入請求的自動載入器
  • Yii 自動載入器支援自動載入擴充套件的類,需要在 composer.json 檔案里正確地定義 autoload 部分

服務定位器(Service Locator)

  • 定義
    • 提供各種應用所需的服務(或元件)的物件
    • 在服務定位器中, 每個元件都只有一個單獨的例項,並通過 ID 唯一地標識
    • 在 Yii 中,服務定位器是yii\di\ServiceLocator或其子類的一個例項
  • 應用場景
    • 最常用的服務定位器是 application(應用)物件,可以通過 \Yii::$app 訪問
    • 每個模組物件本身也是一個服務定位器,模板可視為一個子應用
  • 使用服務定位器
    • 註冊相關元件
      • 通過yii\di\ServiceLocator::set()方法進行相關元件註冊。
      • public void set ( $id, $definition )
      • $definition可以是類名,配置陣列,php 可呼叫物件,或者本身就是一個物件例項
    • 允許通過元件 ID 像訪問一個屬性值那樣訪問一個元件
      • 服務定位器會返回同一個元件的單例
      • yii\di\ServiceLocator::has()檢查某元件 ID 是否被註冊
      • yii\di\ServiceLocator::get()
  • 遍歷樹(Tree traversal)
    • 模組允許任意巢狀;Yii 應用程式本質上是一個模組樹
  • 模組中元件的配置決不會與來自父模組中元件的配置合併

依賴注入容器

  • 依賴注入容器是一個物件,知道怎樣初始化並配置物件及其依賴的所有物件
  • Yii 通過 yii\di\Container類提供 DI 容器特性
    • 構造方法注入
      • 容器會嘗試獲取它所依賴的類或介面的例項,然後通過構造器將其注入新的物件
    • 方法注入
      • 可以提供僅由類的單個方法需要的依賴關係
    • Setter 和屬性注入
      • Setter 和屬性注入是通過配置提供,該配置會提供給容器用於通過相應的 Setter 或屬性注入依賴
    • PHP 回撥注入 (PHP Callable Injection)
      • 容器將使用已註冊的 PHP 回撥來構建類的新例項

yii\di\Container::get()方法將其第三個引數作為配置陣列應用於正在建立的物件 如果該類實現yii\base\Configurable介面(例如 yii\base\BaseObject),則配置陣列將作為最後一個引數傳遞給類建構函式

  • 註冊依賴關係
    • yii\di\Container::set()註冊依賴關係
    • 註冊會用到一個依賴關係名稱和一個依賴關係的定義, 鍵值對可遞迴,方便容器管理例項,類似 laravel 的別名系統
    • 依賴關係名稱可為類名,介面名或一個別名,依賴關係的定義可以是類名,配置陣列,一個 PHP 回撥
    • 通過set()註冊的依賴關係,在每次使用時都會產生一個新例項
    • 使用yii\di\Container::setSingleton()註冊一個單例的依賴關係
  • 解析依賴關係
    • 依賴關係解析是遞迴式進行
    • 註冊依賴關係後,容器會自動解析依賴關係, 將依賴例項化並注入新建立的物件
    • 依賴關係名,可以是通過set()setSingleton()註冊的,也可以是一個類構造器引數列表和一個configuration用於配置新建立的物件
  • 使用依賴注入
    • 在應用程式的入口指令碼中引入Yii.php檔案時,Yii就建立了一個 DI 容器
    • 該 DI 容器可以通過Yii::$container訪問
    • 當呼叫Yii::createObject()時,此方法實際上會呼叫這個容器的 get () 方法建立新物件
    • 在部件呼叫中給出的屬性將始終覆蓋 DI 容器中的定義,若報錯無法被例項化,需要告知容器如何處理依賴關係
  • 高階實用性
    • 可一次配置多個定義 , 將配置陣列傳遞給setDefinitions()setSingletons()方法
    • 配置陣列格式
      • key:類名稱,介面名稱或別名
      • value:與 class 關聯的定義,class關聯的定義,‘identifies引數值將傳遞給 set () 方法
      • 可以選擇將依賴項的建構函式引數作為第三個引數
      • Instance::of('tempFileStorage')符號,Container將隱含地提供一個用tempFileStorage名稱註冊的依賴項
        • 應用場景 內部配置依賴項
    • 通過 set () 註冊的依賴項將在每次需要時例項化
  • 依賴關係註冊使用
    • 應用開發在入口註冊依賴關係
    • 擴充套件開發,則在擴充套件引導類中註冊依賴關係
  • 小結
    • Yii 在依賴住入(DI)容器之上實現了它的服務定位器
    • 當一個服務定位器嘗試建立一個新的物件例項時,它會把呼叫轉發到 DI 容器

更多學習內容可以訪問【對標大廠】精品PHP架構師教程目錄大全,只要你能看完保證薪資上升一個臺階(持續更新)

還有更多進階學習資料領取噢進階PHP月薪30k>>>架構師成長路線【視訊、面試文件免費獲取】