編者按:Discuz! X2.5 RC 版本已於上週釋出,《站長》 雜誌首次連線 Discuz! 開發人員,為站長詳細解讀 Discuz! X2.5 在系統架構、效能負載、功能元件、應用中心等方面的特色與改進。小編特別請到了 Discuz! 開發組成員 bilicen,由他為我們介紹開發人員傾注大量時間與精力進行程式碼重構的底層架構。

《站長》:bilicen 你好!Discuz! X2.5 在系統架構方面進行了哪些改進呢?

bilicen:我們主要進行了六個方面的改進,主要包括:

1 、程式底層架構的改進;2 、使用者輸入資料的處理;3 、資料庫 DB 層的改進;4 、記憶體級快取層的最佳化;5 、多伺服器分庫分散式部署;6 、主要效能瓶頸點的最佳化。經過這六個方面的改進,Discuz! X2.5 的系統架構全新改造,承載能力更強了,並且支援各種第三方外掛、模板的擴充套件,能適應論壇未來的發展需要。

《站長》:為什麼要對系統架構進行如此大幅的改動呢?

Bilicen:站長的需求是無限的,而論壇功能是有限的,論壇系統架構的承載能力更加有限。為了滿足更多站長需求,首先就要改變系統架構。之前的論壇版本更像是普通貨輪,它承載的貨物有限;而 Discus! X2.5 就像是諾亞方舟,它可承載多種多樣的事物,表現在論壇層面就是新版支援站長需要的各種功能、外掛與拓展。

《站長》:在系統架構的六個方面改進中,能否為我們選取一點著重介紹下?

Bilicen:這裡我著重介紹下 Discus! X2.5 在底層架構方面的改進吧,也就是加固 Discuz! X2.5 方舟骨架。首先,我們要求 PHP 版本大於 5.1,拋棄了對 PHP4 的支援;其次,我們大量使用了物件導向程式設計 (OOP),使程式碼的重用性和維護性更高;再次,實現了程式運程過程中按需載入,減少一個程式中對非必要的檔案的解析,按需載入主要是針對類檔案;最後,為了實現程式的按需載入,對目錄名、檔名和類名的要求如下:

類檔案存在/source/class 目錄中,類名和檔名相同,一個類一個檔案,類名以下劃線 (_) 分隔,第一個下劃線之前部分為目錄名,沒有下劃線的類名直接放/source/class/目錄下。產品中個別特殊類由於歷史原因無法實現自動載入,需手動處理 include 或 require 。

《站長》:在底層架構的改進中,肯定會涉及一些核心檔案的改造吧,那主要的改造思路是什麼呢?

Bilicen:主要改造思路是採用新的底層架構介面,以及避免底層架構的臃腫。我們改造了 class_core.php 入口檔案以及 function_core.php 減肥之術等 2 個核心檔案。關於這方面程式碼有興趣的朋友可參考我提供的附件 (附 1) 。

《站長》:在資料層隔離方面,你們主要做了哪些工作呢?

Bilicen:對資料層隔離,首先要對原 DB 類檔案進行改進,同時系統的邏輯層不會出現直接運算元據庫的 SQL 語句。舉例來說:當你需要在 Discuz! X2.5 方舟上裝載一批集裝箱貨時,你可以將它們全部放在甲板上,但不能把它們放在方舟的船艙、駕駛室等部位,以保障方舟的安全駕駛與穩定航行。

以程式碼編寫為例,之前的程式碼是這樣寫的:

$rushresult = DB::fetch_first("SELECT * FROM ".DB::table('forum_threadrush')." WHERE tid='$_G[tid]'");

現在,在新的架構體系下,程式碼實現已經如下:

$rushresult = C::t('forum_threadrush')->fetch($_G['tid']);

可以看出,資料讀寫已經完全封裝,在程式的業務邏輯層不會出現直接運算元據庫的 SQL 語句。感興趣的讀者,也可以參考 forum_viewthread.php 檔案的編寫程式碼對比。

《站長》:資料讀寫封裝對站長有哪些好處呢?

Bilicen:好處是顯而易見的,資料層隔離 (附 2) 使得 Discuz! X2.5 系統更加安全、拓展性更強、負載能力更高,也為記憶體級快取層增加和資料庫分散式部署奠定了基礎,第三方外掛不必再跟隨者系統架構的升級而升級。這就像文章開頭所說的,從貨輪升級為諾亞方舟,不僅更加穩定與安全,並且支援各種各樣的功能外掛,能滿足更多站長多樣化需求。

《站長》:謝謝 Bilicen 。下一期請為我們講解下 Discuz! 在分伺服器部署方面的創新。

附 1:關於 class_core.php 入口檔案以及 function_core.php 減肥之術:

Class_core.php 是入口啟動檔案,主要實現了以下功能:

1 、註冊 autoload 方法和異常處理方法;

2 、 C::t 方法的實現;

3 、 memory 的初始化;

4 、建立 discuz_application 例項 (discuz_application 是原來 discuz! X2 的 discuz_core);

5 、簡寫類的對映:

class C extends core {}

class DB extends discuz_database {}

function_core.php 是系統的核心函式庫檔案,隨著系統功能的豐富,函式庫越來越大,慢慢地變成了系統快速啟動的負擔,為此我們將 function_core 中的函式按功能拆分到不同的類檔案中,實現程式的按需載入;原有函式名保留不變,做相應類靜態方法的對映,相容產品和外掛的用法。

具體做法是在 source/class 目錄增加兩個目錄,helper 和 lib source/class/helper 目錄中的檔案為函式的分類集合,類的靜態方法,可直接使用不用例項化 source/class/lib 目錄中的檔案為工具類的集合類檔案,使用時需例項化。

附 2:資料層隔離:

1 、 addslashes 的處理

insert(),update(),delete() 方法對傳入其的陣列形式的引數進行安全處理:intval 或 addslashes,字串形式的引數將不處理,請注意;

2 、新新增的方法

fetch_all($sql),order(), limit(),field() 等方法,其中 fetch_all 方法以陣列方式返回查詢多條記錄資料,且可以設定資料的 KEY 值使用某欄位值;

3 、增加 SQL 語句 format 的支援

例:查詢 10 個使用者 uid 大於 100 的使用者資料,以 uid 為返回結果陣列的 key

$arr = DB::fetch_all(‘SELECT * FROM %t WHERE uid>%d LIMIT %d’, array(‘common_member’, ‘100’, ‘10’), ‘uid’);

支援的 fomat 有:

%t

DB::table()

%d

intval()

%s

Addslashes()

%n

id IN (1,2,3)

%f

sprintf(‘%F’, $var)

%i

直接使用不進行處理

4 、返回值的處理

在非 UNBUFFERED 的情況下:

INSERT SQL 語句返回 insert_id()

UPDATE 和 DELETE SQL 語句返回 affected_rows()