摘自:http://yeyuan.iteye.com/blog/930727
PS:本人剛接觸discuz論壇,php水平有限,當中的理解,如有不正確之處,歡迎指出
------------------------------------
第一個文件相當於控制器(C),比如forum.php(根目錄下,相當於大模塊,應該再加上小模塊控制 module),功能是將相應的請求發送到相應的邏輯處理模塊
第二個文件就是業務邏輯處理 如forum_post.php(source\module\forum\forum_post.php,Module相當於小模塊、功能點) ,功能是帖子的發布處理
在第二個文件當中再調用相應的函數庫,處理模塊業務 如function_forum.php(source\function\function_forum.php)
函數庫則調用數據庫持久層的表對象(M) 在class/table 下的數據表對象與數據庫發生交互,比如source\class\table\table_forum_post.php
第三個文件就是模板文件了(V),將獲取到得數據填充到頁面各模塊分工明細,維護簡單
如果需要添加新的模塊,可以仿造這種模式,而不會太復雜大致是這個樣子的
------------------------------------
依我的理解,discuz的MVC結構是這樣的:
Model即邏輯處理,應該是source/function,這里面的一些函數是對數據庫(表對象class/table),緩存,內存,配置等一些的相關操作。
Control即控制器,應該是source/module對應相關的模塊,比如門戶的相關操作,就在portal文件夾下,論壇的相關操作是在forum文件夾下。
View模板即最終呈現給用戶看的則是template()這個函數,稍后可以簡單的說下這個函數的相關過程。
接下來說下執行的相關流程,先看下一些代碼
- define('APPTYPEID', 4);
- define('CURSCRIPT', 'portal');
- require './source/class/class_core.php';//這個文件是核心文件,初始化工作是在這里進行的。
- $discuz = & discuz_core::instance//實例化對象,這里是一個單件模式
- $cachelist = array('userapp', 'portalcategory');
- $discuz->cachelist = $cachelist;//聲明緩存列表
- $discuz->init();
- //進行初始化,環境檢查,讀取配置,設置內存等
- require DISCUZ_ROOT.'./source/function/function_home.php';
- require DISCUZ_ROOT.'./source/function/function_portal.php';
- //包含protal.php對應的核心函數文件
- if(emptyempty($_GET['mod']) || !in_array($_GET['mod'], array('list', 'view', 'comment', 'portalcp', 'topic', 'attachment'))) $_GET['mod'] = 'index';
- 檢查mod,是否在mod列表里,如果不在或者不對應,則默認為index
- define('CURMODULE', $_GET['mod']);
- runhooks();//這個是用來檢查加載插件的
- $navtitle = str_replace('{bbname}', $_G['setting']['bbname'], $_G['setting']['seotitle']['portal']);
- require_once libfile('portal/'.$_GET['mod'], 'module');
- //這個是用來加截source/module下的對應文件的。
define('APPTYPEID', 4); define('CURSCRIPT', 'portal'); require './source/class/class_core.php';//這個文件是核心文件,初始化工作是在這里進行的。 $discuz = & discuz_core::instance//實例化對象,這里是一個單件模式 $cachelist = array('userapp', 'portalcategory'); $discuz->cachelist = $cachelist;//聲明緩存列表 $discuz->init(); //進行初始化,環境檢查,讀取配置,設置內存等 require DISCUZ_ROOT.'./source/function/function_home.php'; require DISCUZ_ROOT.'./source/function/function_portal.php'; //包含protal.php對應的核心函數文件 if(empty($_GET['mod']) || !in_array($_GET['mod'], array('list', 'view', 'comment', 'portalcp', 'topic', 'attachment'))) $_GET['mod'] = 'index'; 檢查mod,是否在mod列表里,如果不在或者不對應,則默認為index define('CURMODULE', $_GET['mod']); runhooks();//這個是用來檢查加載插件的 $navtitle = str_replace('{bbname}', $_G['setting']['bbname'], $_G['setting']['seotitle']['portal']); require_once libfile('portal/'.$_GET['mod'], 'module'); //這個是用來加截source/module下的對應文件的。
接下來我們可以看下libfile()這個函數
- //該文件在source/function/function.core.php
- //按上面的傳入兩個參數libfile("portal/index","module")
- function libfile($libname, $folder = '') {
- $libpath = DISCUZ_ROOT.'/source/'.$folder;
- //$libpath = "disucz/source/module"
- if(strstr($libname, '/')) {
- list($pre, $name) = explode('/', $libname);
- return realpath("{$libpath}/{$pre}/{$pre}_{$name}.php");
- } else {
- return realpath("{$libpath}/{$libname}.php");
- }
- //$libname=protal/protal_index.php
- //那么返回的文件就應該是disucz/source/module/protal/protal_index.php
- }
//該文件在source/function/function.core.php //按上面的傳入兩個參數libfile("portal/index","module") function libfile($libname, $folder = '') { $libpath = DISCUZ_ROOT.'/source/'.$folder; //$libpath = "disucz/source/module" if(strstr($libname, '/')) { list($pre, $name) = explode('/', $libname); return realpath("{$libpath}/{$pre}/{$pre}_{$name}.php"); } else { return realpath("{$libpath}/{$libname}.php"); } //$libname=protal/protal_index.php //那么返回的文件就應該是disucz/source/module/protal/protal_index.php }
那么我們就來看下protal_index.php這個文件
- if(!defined('IN_DISCUZ')) {
- exit('Access Denied');
- }
- //上面是用來檢查discuz核心文件是否加載,
- $navtitle = str_replace('{bbname}', $_G['setting']['bbname'], $_G['setting']['seotitle']['portal']);
- if(!$navtitle) {
- $navtitle = $_G['setting']['navs'][1]['navname'];
- } else {
- $nobbname = true;
- }
- $metakeywords = $_G['setting']['seokeywords']['portal'];
- if(!$metakeywords) {
- $metakeywords = $_G['setting']['navs'][1]['navname'];
- }
- $metadescription = $_G['setting']['seodescription']['portal'];
- if(!$metadescription) {
- $metadescription = $_G['setting']['navs'][1]['navname'];
- }
- 上面是一些文件頭信息,
- include_once template('diy:portal/index');
if(!defined('IN_DISCUZ')) { exit('Access Denied'); } //上面是用來檢查discuz核心文件是否加載, $navtitle = str_replace('{bbname}', $_G['setting']['bbname'], $_G['setting']['seotitle']['portal']); if(!$navtitle) { $navtitle = $_G['setting']['navs'][1]['navname']; } else { $nobbname = true; } $metakeywords = $_G['setting']['seokeywords']['portal']; if(!$metakeywords) { $metakeywords = $_G['setting']['navs'][1]['navname']; } $metadescription = $_G['setting']['seodescription']['portal']; if(!$metadescription) { $metadescription = $_G['setting']['navs'][1]['navname']; } 上面是一些文件頭信息, include_once template('diy:portal/index');
這個template函數,代碼比較長,我就不貼了,大致說下功能。
template主要的功能是用來生成緩存文件的名字,只是用來生成這個名字,實際並未生成,真正生成的是template函數最后的那個checktplrefresh(),看名字,應該猜得出,是檢查模板是否更新
看下checktplrefresh()這個函數
- function checktplrefresh($maintpl, $subtpl, $timecompare, $templateid, $cachefile, $tpldir, $file) {
- static $tplrefresh, $timestamp;
- if($tplrefresh === null) {
- $tplrefresh = getglobal('config/output/tplrefresh');
- $timestamp = getglobal('timestamp');
- }
- //上面的那段我還不知道是干啥來着,
- if(emptyempty($timecompare) || $tplrefresh == 1 || ($tplrefresh > 1 && !($timestamp % $tplrefresh))) {
- if(emptyempty($timecompare) || @filemtime(DISCUZ_ROOT.$subtpl) > $timecompare) {
- require_once DISCUZ_ROOT.'/source/class/class_template.php';
- $template = new template();
- $template->parse_template($maintpl, $templateid, $tpldir, $file, $cachefile);
- return TRUE;
- }
- }
- return FALSE;
- }
- 下面的這個判斷主要是看是否在緩存時間內,如果在緩存時間內,則返回false,直接包含之前生成的緩存文件,如果不在緩存時間之后,則進行重新解析。完了之后,就會執行解析好的php緩存文件。顯示到前台,大家可以看下parse_template()這個函數用了很正則去解析模板。這個就不多介紹了,大家可以去看下。
- 由此以來,先是調用source/module/下的相關文件進行讀取數據庫或者是讀取緩存數據的相關功能把,相關變量賦值然后用template和template類進行對模板解析,變量替換,然后顯示到前台,大致的過程就是這樣的。
- 當然中間還有一些緩存的相關判斷,這部分還在研究之中,稍候會貼出來。
- 以上可能會有理解錯誤的地方,歡迎指出或補充