1.內容介紹 深入解析tp5.1與laravel 中Facade底層原理實現 1. 什麼是Facade 2. 為什麼需要有什麼好處 3. Facade實現原理 4. 功能實現、 5. 容器註入 2.知識講解 0.什麼是Facade??為什麼需要?有什麼好處 專業解釋: 門面模式(Facade)又稱外 ...
1.內容介紹
深入解析tp5.1與laravel 中Facade底層原理實現
1. 什麼是Facade
2. 為什麼需要有什麼好處
3. Facade實現原理
4. 功能實現、
5. 容器註入
2.知識講解
0.什麼是Facade??為什麼需要?有什麼好處
專業解釋:
門面模式(Facade)又稱外觀模式,用於為子系統中的一組介面提供一個一致的界面。門面模式定義了一個高層介面,這個介面使得子系統更加容易使用:引入門面角色之後,用戶只需要直接與門面角色交互,用戶與子系統之間的複雜關係由門面角色來實現,從而降低了系統的耦合度。
通俗解釋:
門面為容器中的類提供了一個靜態調用介面,相比於傳統的靜態方法調用, 帶來了更好的可測試性和擴展性,你可以為任何的非靜態類庫定義一個facade類。
對於一個非靜態的類,如果要調用這個類的方法我們可能就是要通過new 創建這個對象,然後再通過 -> 調用這個類的方法
如:
我們要調用這個類的方法就是
這樣調用類,但是如果調用的次數多了,自己每次調用這方法都要創建類從寫法上就覺得不是很好而我們更多的是想直接以靜態通過類名::方法() 的方式調用,並且開發速度不快以及不夠優雅,
而如果我們使用facade模式
給這個類一個靜態代理對象,然後我們就可以通過靜態的方式調用
當然如上是TP5手冊的例子
1.自己實踐一次
首先我們可以創建一個工具類UserUtil
如果說我們需要使用這個類的時候,比如:在index控制器中進行調用UserUtil中的index方法
如上代碼,這就是我們一般的操作方式。
這樣我們就會看起來不夠的優雅。我在使用的時候還需要new出這個對象,我不想new怎麼辦?
我們修改一下UserUtil中的index方法,用static修飾
然後在控制器中,就可以通過類名的方式靜態的調用了
但是實際上這樣並不是很好,如果說我們的UserUtil中會定義很多方法,如果說我們的Util中不止一個UserUtil,比如有TreeUtil等等其他類,這個時候我們就需要一一的給這些類定義static很明顯就不夠優雅,同時在記憶體中會一直保存這些靜態屬性,有很多使用其實次數不多但是也會保存很顯然會占用一部分空間和資源。
其實還有一個最大的問題就是擴展和維護不強。
比如我們在做項目的時候我們在1.0版本的時候我們可能會在index方法添加很多代碼,同時又有很多其他的方法,可是有一天產品經理需要改需求,這個時候你發現你定義的這個類沒用了不滿足這個需求的時候那麼我們就只有需改源碼
那麼接下來我們就需要對於這個UserUtil中的方法需改,可是當需改一個類的時間比一個新建一個類的時間要多的時候最好的辦法就是重寫。這個時候我們可能在接下來的操作中要需改很多調用這個UserUtil的地方。腫麽辦??
我們就可以使用façade作為這種類代理。
首先:我們先把UserUtil類中的index需改回來
然後創建一個app\facade\UserUtil.php的門面代理類
在類中繼承Facade,同時重寫think\Facade類中的getFacadeClass方法
在方法中return的值就是 這個類要代理的實際類 你也可以是
return “app\util\UserUtil”;
只是那樣可以顯得高大上哈哈哈~~~
然後我們在控制器中使用
註意!引入的是app\facade\UserUtil
然後就成功了。
在代理類中除了重寫getFacadeClass方法外還可以使用think\Facade的bind方法
首先我們一起看一下tp5.1對於框架是怎麼對於核心類庫用facade代理的
打開thinkphp\base.php這個文件,就可以發現tp5.1的核心類庫是通過Think\Facade中的bind方法進行了定義
同時又通過Think\Loader中的addClassAlias方法對於核心類別名註冊
那麼我們也可以模仿
首先把app\facade\UserUtil類進行處理
不重寫getFacadeClass方法
然後我們在app\common.php中寫
然後使用
Success
2.Tp5.1解析Facade
執行User::index()時
會進入think\Facade類中
因為沒有實際調用的方法這個時候執行__callStatic
通過createFacade創建實際被代理類的實例
首先判斷是否創建過
執行子類重寫的定義被代理類的方法
如果沒有重寫定義這個被代理類的地址
這個時候就檢查是否被綁定
重邦定的$bind中獲取實例
創建實例並執行實例的方法