編者按: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()