首頁  >  文章  >  php框架  >  ThinkPHP門面源碼解析

ThinkPHP門面源碼解析

咔咔
咔咔原創
2020-11-05 12:02:372174瀏覽

本文主要描述了門面的使用和實作過程,並且對原始碼進行剖析。

前言

使用框架的夥伴應該都知道在5.1時框架新增了一個特性那就是本文將要寫的門面,也就是facade這個特性。

使用過這個特性的都明白其中的好處,那就是方法調用可以直接靜態進行調用,不用再使用關鍵字static來定義。

接下來喀喀爾將會從以下幾個方面帶著大家探索屬於門面的故事。

一、簡單認識一下在框架中的門面的好處

在之前有寫過設定檔加載一文,在那一文中的最後提到過配置資訊獲取的幾種方式。

其中有一種方式就是Config::get(),到這篇文章應該都知道使用Config獲取配置資訊時,必須先得引入use think\facade\Config,又因為在系統中註冊了別名,所以直接使用use Config即可。

雖然說我們使用的是use think\facade\Config,但實際呼叫的方法卻是thinkphp/library/think/Facade.php中的__callStatic方法。

然後會執行同檔案的createFacade方法。

雖然說現在還沒看原始碼,看著知道就好了,在呼叫createFacade方法時是直接從容器類別裡邊取得的。

在學習容器時我們都知道容器是使用了註冊樹模式,需要使用對應物件實例的時候就可以直接獲取,這樣就避免了一個類別反覆的創建。這就是其中的一個優點。利用容器的特性

對於先前使用config來說,需要使用config的命名空間,然後進行實例化才能進行呼叫。

如果此時config不讓使用了,需要使用自己建立的config類,如果沒有使用門面模式,就需要修改大量的程式碼,而且是全域的。

但是如果使用了框架中的facade門面模式之後,你就只需要重寫getFacadeClass這個方法即可,只需要改變裡邊的返回結果誒自己定義的即可,因為對於其它檔案呼叫的地方它們不關心實例呼叫的是什麼,只關心方法名稱和傳回結果。

二、學習框架中facade的使用

#先建立一個控制器Facade,並且寫上以下內容。

這裡只是簡單的使用門面的方式來取得設定檔資訊。

ThinkPHP門面源碼解析這裡可以看到使用的是use Config,這個就是config類別的別名。

別名的設定是在base.php中設定的。

ThinkPHP門面源碼解析在框架中如何正確的使用facade呢!

在app目錄下新建一個資料夾facade,用來專門存放門面類別。

這裡創建了一個Sessions的類別。

ThinkPHP門面源碼解析先做一個測試,偵測程式碼是否寫的有問題。在控制器的facade檔案中進行測試。

這就是沒有使用門面時的處理方式,需要引入對應的類,然後進行實例化,在用實例化的類別進行方法呼叫。

ThinkPHP門面源碼解析列印結果,結果就是我們預期的結果。

ThinkPHP門面源碼解析那麼這份程式碼怎麼改為門面模式呢!跟著咔咔的腳步一步一步的來。

先在kaka目錄下建立兩個目錄,分別為facade和util

ThinkPHP門面源碼解析為什麼要建立這兩個資料夾呢! util大家應該都知道那就是工具類,這種類文件是可以在其它專案中公用的。

也就是說我們只需要實作一份然後在其它專案中用的時候直接拿過去就可以了。

所以就可以直接把檔案複製到util目錄下,記得修改命名空間即可。

ThinkPHP門面源碼解析然後在到facade目錄下新建一個Sessions的類,並且繼承Facade。然後寫上一下內容。

ThinkPHP門面源碼解析此時我們在來到控制器進行測試一下。

會發現結果跟之前是一致的,但是很明顯的一個差異就是使用了facade模式後,可以直接使用靜態方式進行呼叫。

還記得在之前說過門面的一個好處嗎?

假設這個Sessions工具類別在未來的一天停止使用了,那麼我們只需要修改getFacadeClass方法裡邊的內容即可。

ThinkPHP門面源碼解析ThinkPHP門面源碼解析

三、最佳化在框架中facade的使用

在上文中我們從實例化類別到使用門面方式實作了同一個功能。

雖說想要實現的效果顯示出來了,但是程式碼還是不夠簡潔優美的,結構也比較混亂。

接下來喀喀爾會提供大家一個可行的方案,如果你有其它的方案可以提出來哈!評論區見。

在正常開發工作中自訂的門面類別不可能只有一個或幾個,在複雜的專案中門面類別會有很多。

既然多,那就需要管理。

ThinkPHP門面源碼解析首先建立一個屬於門面的設定類別。

並將代理類別和實際類別對應起來,然後設定別名。

ThinkPHP門面源碼解析此時需要建立一個鉤子文件,將門面類別註冊和門面類別名稱註冊都放在裡邊執行。

ThinkPHP門面源碼解析還有最後一步,那就是鉤子檔案雖然創建了但是沒有執行。

那麼鉤子檔案應該什麼時候執行呢!那就是在應用初始化的時候進行載入。

在TP5.1中套用初始化的設定是在application/tags.php這個檔案。

在套用初始化的設定項裡把鉤子檔案配置進去即可。

ThinkPHP門面源碼解析測試

最後一步就是測試了,還是執行application/index/controller/Facade.php檔案中的getUserInfo方法。

根據測試結果可以得知我們的方案程式碼編寫沒有問題。

ThinkPHP門面源碼解析ThinkPHP門面源碼解析這裡有沒有發現一個問題,就是既然在鉤子中定義了門面類別的別名了,但是這裡並沒有使用。

接下來我們使用別名來測試一下。

ThinkPHP門面源碼解析ThinkPHP門面源碼解析

四、門面類別原始碼解析

在解析原始碼之前先認識倆個方法。

  • __callStatic:當存取不存在的靜態方法時,會呼叫此方法。
  • call_user_func_array:可以直接使用此函數直接呼叫函數。

我們就從取得設定檔開始解析

ThinkPHP門面源碼解析執行Config::get('facade.');會執行到檔案thinkphp/library/think/facade/Config.php中。

在這個檔案中就是之前說的,如果存在getFacadeClass方法就會直接傳回對應的別名。

如果不存在的話就需要使用bind方法來進行門面綁定。

這裡如果不明白就需要去文檔好好看看門面那一章哈!

ThinkPHP門面源碼解析在上邊類別中是不存在get方法的,所以就會直接呼叫thinkphp/library/think/Facade.php檔案中的__callStatic方法。

這個方法就是文章開頭就直接說明的,在存取不存在的靜態的方法時則會呼叫此方法。

ThinkPHP門面源碼解析接著就會執行本類別中的createFacade這個方法

在這個方法裡邊有一行程式碼是這個樣子的$facadeClass = static ::getFacadeClass();這段程式碼會在下文做詳細的說明。

因為子類別中也有同樣的方法,在本類別中也有同樣的方法但是在本類別中的方法是沒有任何傳回值的。

這時你有沒有一絲絲的困惑,這裡使用的static到底會執行哪裡的方法。或者這樣想,為什麼會執行子類別的方法。

保留這些疑問將會在下文給你細細的講來,先來把門面類別的源碼看完。

在這個方法中主要看我圈起來的幾個地方。

第一處就是從子類別的getFacadeClass方法取得類別的別名。

第二處是當子類別沒有getFacadeClass方法時,從手動綁定的屬性中取得。

第三處就是之前文章提到的容器了,這裡就不對這裡做詳細說明了,如果不會的點開主頁去看之前的文章。

ThinkPHP門面源碼解析
createFacade方法

#五、static關鍵字

##在這裡不得不說明一下static這個關鍵字。

新學習的夥伴估計只能知道static是用來定義靜態變數和靜態方法的。

當然這裡不會去跟大家說怎麼定義靜態方法和靜態變量,而是說一個非常非常小的細節點。

先看一個實例,這個實例也是在閱讀門面原始碼時,喀喀爾根據門面原始碼改編過來的。

咔咔在這裡新建了兩個文件,分別為test和test1。

test繼承test1文件,而且都有同樣的方法getKaka。

ThinkPHP門面源碼解析新兩個檔案

test的原始碼

##test原始碼ThinkPHP門面源碼解析
test1原始碼

控制器進行呼叫ThinkPHP門面源碼解析

ThinkPHP門面源碼解析列印結果ThinkPHP門面源碼解析這時候有沒有一點點疑惑,這裡怎麼印出來的是147,而不是456呢!

修改test1的程式碼,把static改為self

ThinkPHP門面源碼解析#列印結果

ThinkPHP門面源碼解析使用self的程式碼相信大家都看的明白,那為什麼使用static就出現了有可能不太懂的結果呢!

此時就是文件開始運作了,但當你開啟PHP文件會發現,在static這篇文章中並沒有對這類情況作出說明。

經過咔咔多次測試和查閱資料,最終總結結果如下。

static::$test  如果有被繼承的話預設呼叫子類,否則呼叫的是自身

self::$test    如果有被繼承的話,預設呼叫本類

放在本實例中來說明就是,當test繼承test1時。

在test1中使用static呼叫方法getKaka時,預設呼叫的是test類別中的getKaka,也就是子類別的方法。

在test1中使用self呼叫方法getKaka時,預設呼叫的是test1類別中的getKaka,也就是本類別的方法。

這個小小的細節也是喀喀無意間發現的,如果有任何不對的地方可以提出來,喀喀爾做出修改。

因為在繼承這方面還有另一種情況,咔咔私下會進行測試,這裡就不說明了。

這裡對這個static做出解釋主要是為了解釋thinkphp/library/think/Facade.php檔案中這個行程式碼。

因為這行程式碼呼叫的方法在子類別和父類別都存在,所以咔咔為了不讓大家出現迷惑就寫出來做一個簡單的介紹。

ThinkPHP門面源碼解析
thinkphp/library/think/Facade.php

六、總結

先來一份門面流程圖,可以更清楚的看到門面類別的具體執行流程。

ThinkPHP門面源碼解析門面類別的原始碼很簡單,除了幾個不太常見的知識點,程式碼相信都看的明白。

這裡主要是對閱讀完門面類別後,做一個小總結。

門面類別主要是結合了容器來實現的一個功能,因為需要容器來傳回對應的實例,關於容器的文章也已經完成了,如果對容器有不會的可以在文章的開頭去看對應的文章即可。

本文中為大家介紹了門面在容器中如何使用,並且給大家提供了最優的使用方式,這裡的最優是咔咔咔個人見解,因為這種方式咔咔使用了接近倆年了。

無論從程式碼的健全性或擴充性都是非常實用的。

再來就是關於static關鍵字,給大家做的一點點冷門知識得補充,當一個類別繼承一個類別時,在父類別實用static關鍵字時,預設呼叫的子類別的方法。

這裡的總結只是針對於本文的實例。

其實在這裡咔咔也想跟大家說一個點就是return call_user_func_array([static::createFacade(), $method], $params);

#因為在以前的用法的哥參數就直接是方法,但是在這裡碰到了數組形式,那麼這個數組中的兩個值都代表的是什麼呢!

第一個值為實例,第二個值為實例中的方法。

關於call_user_func_array這個方法的使用咔咔就不去做案例給大家看了,只需要知道它會去執行傳入得方法即可。

到這裡關於門面的源碼解析就結束了,最重要的還是理解容器,因為門面就是在容器的基礎上實現的,這也就是咔咔先寫容器在寫門面的原因。

還有就是關於門面的使用咔咔也給出了方案,如你有更好的方案可以在評論區給一個大概的思路。

堅持學習、堅持寫博、堅持分享是咔咔從業以來一直所秉持的信念。希望在偌大互聯網中咔咔的文章能帶給你一絲絲幫助。我是咔咔,下期見。

以上是ThinkPHP門面源碼解析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn