Yii2框架是一個很是龐大可是並不臃腫的 php 框架。使用 Yii2 框架,能夠極大的提高開發效率。 秉持着要知其然也要知其因此然的思想,花了一週的時間,看了 linuor 的 《深刻理解Yii2.0》 根據個人理解梳理了一下 Yii2 框架的總體結構。此後簡稱框架。php
Yii 框架基礎
此框架的三個基礎概念:程序員
- 屬性
- 事件
- 行爲
畢竟三生萬物。web
屬性
一看到這個詞可能很迷惑,那麼什麼是屬性呢。 好比說,你如今正在玩一款角色扮演的遊戲,角色雙手分別有一把 十方大劍
,一個 十方盾牌
。 那麼從面向對象的角度而言,你的角色類須要有 左手武器
和 右手武器
兩個成員變量。 而且角色類能夠從 左手武器
和 右手武器
中得到 力量屬性。數據庫
這麼一說屬性這一律念,就很容易理解了。設計模式
事件
仍是以角色扮演遊戲爲例(這裏要對不起不玩遊戲的朋友了,原諒我匱乏的想象力,或者你有好的比喻也能夠跟我說),遊戲裏面都有任務系統,而任務會分爲主線任務和支線任務,在作主線任務是一般會觸發一系列的支線任務。這些支線任務的觸發就能夠認爲是一系列的事件。網絡
行爲
框架的行爲也可使用角色扮演遊戲來舉例,你在 無盡荒原 撿到了一本魔法書,學會了禁咒魔法,召喚神龍
。 因而你把程序一改,給你的類加一個召喚魔法的方法,這是不可能的。咱們必須讓你的類擁有一個動態添加方法的功能,因而全部拿到魔法書的人或者限定職業的人,都能學會這個禁咒,這就是 行爲
的做用,動態給類增長方法。架構
以上,有了這三個 框架 實現的武器,咱們才能更快速和靈活的搭建上層的程序。框架
設計模式
依賴注入
框架採用瞭如今世面上面最多見的一種模式, MVC 模式,具體細節再也不闡述,如今網上關於 MVC 的介紹能夠說是爛大街了。 MVC 只是一種大框架上的設計模式,其核心思想是分層,最終目的是解耦。框架在 MVC 的基礎上,應用了不少經典的設計模式以及後來發展的設計模式。yii
其中最重要的就是:this
- 依賴注入
- 服務定位器。
那麼什麼是依賴注入呢 先來一段沒有依賴注入的代碼:
<?php // 這段代碼將 db1 中的t1表的數據備份到 db2 庫的 t2 中。 // 所使用的變量都在邏輯過程當中申請。 class Archive { public function doArchive() { $dataDB = new DB1(); $data = $dataDB->query("select * from t1"); $backDB = new DB2(); foreach ($data as $key => $value) { $backDB->query("insert into t2 values ". implode(',', $value)); } die("備份完成"); } }
那麼若是再來一個需求,讓你把 db3 的數據備份到 db4 中,邏輯相同,那麼你該怎麼辦呢? 有道友就說了,那還不簡單, copy & paste,搞定。 因而,你多了一個方法或者一個類。 一直到你的方法和類增長到10個以上時,你都不會有什麼感受。 直到產品說如今需求變了,讓你把全部的備份庫都改爲 db3,那麼,你就要把手頭的工做都停下來,而後將代碼中的備份庫全改爲 db3。
並且,若是你使用的是靜態語言,那麼,你就要把代碼再從新編譯一遍。關於靜態語言的編譯時長:爲何c編譯須要這麼長時間
那麼就有了下面這種:
class ArchiveNew { private $originDb; private $backDb; public function doArchive() { $dataDB = new $this->originDb(); $data = $dataDB->query("select * from t1"); $backDB = new $this->backDb(); foreach ($data as $key => $value) { $backDB->query("insert into t2 values ". implode(',', $value)); } die("備份完成"); } /** * @param mixed $originDb */ public function setOriginDb($originDb) { $this->originDb = $originDb; } /** * @param mixed $backDb */ public function setBackDb($backDb) { $this->backDb = $backDb; } }
這個方法,把全部的須要用到的數據庫都放到了外面來進行管理,那麼咱們稱這幾個數據庫爲依賴,稱在外部設置數據庫的行爲爲依賴注入。 這只是一種很原始的使用方式,你能夠繼續延伸,將外部依賴放到統一的地方去管理,那麼就有了注入容器(di Container)
服務定位器
服務定位器像是一個註冊中心,向服務定位器中註冊一個 a 服務,可使用 a 這個名字從服務定位器中取出這個服務。
$locator = new ServiceLocator; $locator->set('a'); $locator->get('a');
服務定位器是基於依賴注入的,在獲取服務時,其實會在容器中先註冊一個服務。
請求與響應
這一節其實主要講的就是請求。 請求的內容會比較多,還涉及到網絡協議等知識,這裏再也不展開。 列舉一下重要的幾點:
- 路由美化 (將原始的路由修改爲比較美觀的地址,見導圖 請求部分)
- url 解析(將美化過的路由解析成原始請求)
- 請求管理 (包括請求頭部,請求體,解析器等等)
數據庫
雖然這張圖有些搞笑,可是無疑說明了 數據庫(MySQL)對於 PHP 的重要性。
類型轉換
框架爲了兼容各類數據庫,對數據類型作了多層封裝,而且作了一系列的轉換規則:
事務
框架支持事務嵌套,可是嵌套的事務必須成對出現(注意!!!)。 看到事務這一節的時候,正巧同事出了一個 bug ,在腳本的循環中,出錯以後沒有 commit 或者 rollback ,致使,接下來的生成的事務都成了這個事務的子事務。而框架的嵌套事務,其實是使用代碼模擬的,若是父事務沒有提交,那麼子事務永遠不會提交。
事件
const EVENT_INIT = 'init'; // 初始化對象時觸發 const EVENT_AFTER_FIND = 'afterFind'; // 執行查詢結束時觸發 const EVENT_BEFORE_INSERT = 'beforeInsert'; // 插入結束時觸發 const EVENT_AFTER_INSERT = 'afterInsert'; // 插入以前觸發 const EVENT_BEFORE_UPDATE = 'beforeUpdate'; // 更新記錄前觸發 const EVENT_AFTER_UPDATE = 'afterUpdate'; // 更新記錄後觸發 const EVENT_BEFORE_DELETE = 'beforeDelete'; // 刪除記錄前觸發 const EVENT_AFTER_DELETE = 'afterDelete'; // 刪除記錄後觸發
這些事件和其餘事件沒有什麼分別,都是在特定的時候會執行,就不一一闡述了。
樂觀鎖和悲觀鎖
框架自帶了樂觀鎖的實現,若是有相似需求,能夠在重載yii\db\ActiveRecord::optimisticLock() 方法,返回數據庫中的版本號字段便可。在更新與刪除時,框架會作相應的操做,來保證,更新的數據是本身拿到的數據,而不是被別人給修改過了。 由於悲觀鎖不適用於 web 應用,因此框架並無實現悲觀鎖。
總結
Yii2 框架的總體架構要比 1 版本提高了一個逼格。而且得益於 namespace 特性,框架的目錄結構清晰了不少。 對於不想了解框架底層實現的程序員,能夠僅僅瞭解基本使用,就能夠上手寫業務代碼,而不會影響你的開發效率。 只有當你碰見一個很蛋疼的框架內部報錯或者 bug 的時候,你纔會想到,我去,這怎麼這麼蛋疼,怎麼框架還會有 bug ,可是不少時候是環境、配置或者特定的代碼致使的。若是不瞭解框架的內部邏輯,這個報錯或者 bug 會耽誤你很長時間。