抽點時間講解一下 C::t 方法的簡單使用。
一、 C::t 方法的好處:一是對象清楚,二是對形參格式化處理,三是可集中 SQL 語句,利於維護,四是安全性更高。
二、具體用法,看下面的例子
假設有一個名為 test 的插件,其中關於名為 tbname 的數據表操作的 SQL
舊式寫法
a.inc.php
<?php
……
$query = DB::query('select * from '.DB::table('tbname').' where id='.$id);
while($v = DB::fetch($query)){
……
}
……
?>
改造為 C::t 如下
a.inc.php
<?php
……
$query = C::t('#test#tbname')->fetch_all($id);
foreach($query as $key => $value){
或者將上面的兩行變為一行,以減少行數,如下
foreach(C::t('#test#tbname')->fetch_all($id) as $key => $value){
……
}
……
?>
再新建一個文件夾名為 table,放在插件根目錄下,在 table 中創建一個名為 table_tbname.php 的類文件 (詳見技術文庫的相關説明),該文件的代碼框架如下
table_tbname.php
<?php
if (!defined('IN_DISCUZ')) {
    exit('Aecsse Denied');
}
class table_tbname extends discuz_table{
    public function __construct() {
        $this->_table = 'tbname';
        $this->_pk = 'id';
        parent::__construct();
    }
    /*------------在此處構造 N 多的自定義函數,本例中自定義的函數如下-------------*/
    public function fetch_all($id){
         return DB::fetch_all('select * from %t where id=%d',array($this->_table,$id));
    }
}
?>
C::t 的運用有很多變化,但萬變不離其宗,基本骨架就是上面的樣子。
注意:
1 、自定義函數中有一個同名函數名 fetch_all,雖然名字相同,但內涵不同。本例比較特殊,實際自定義函數名稱你可以隨便起,例如 public
function ldsjglfdjs($id),不一定非要像技術文庫要求那樣規則命名,當然,規則命名更易於辨認理解維護
2 、 SQL 中應當用格式化語句書寫,以保障安全性,其中的%t 代表了對數據表名的格式化,%d 代表了對%id 的格式化,其中的含義請查詢技術文庫"源 DB 類的改進",以瞭解掌握都有哪些格式符及其意義並加以運用。這裏要特別注意%s 和%i 的區別,涉及安全處理問題
3 、雖然不是必須,但我仍建議並強調,以數組形參的形式作為 DB 層封裝函數的第二參數 (如果該函數有此參數的話),例如上例中的
DB::fetch_all(SQL,array(第一形參, 第二形參,...)),某些 DB 層封裝的函數對於有無 $arg 這個數組參數有着不同的執行過
程,將會影響對該參數中的變量是否進行安全過濾的行為
4 、 SQL 中的格式符一定要和數組形參中的變量一一對應,不能顛倒
5 、不提倡舊式的 SQL 寫法,如 DB::fetch_all('select * from '.DB::table('tbname').' where id='.$id),原因見上面的 3
6 、雖然不是必須,但 C::t 方法中自定義函數內最好不要使用諸如 $_GET 、 $_POST 之類的全局變量,應在 C::t 之前賦值後傳入,否則,例如在 DB::query 中使用,如不進行過濾,其安全性將難以保障
7 、大多數被 DB 封裝的常用數據庫操作函數,其參數都將被做安全處理,因此要注意,雖然不是必須避免重複過濾,但應考慮執行效率問題。
8 、注意注意再注意,由於大多數被 DB 封裝的常用數據庫操作函數都要調用內部 query 函數,相當於在外部直接使用 DB::query,而該函數有個特例情況,就是上面 3 所説,因此特別要考慮有無數組形參,進而加固安全性
9 、儘量將 SQL 集中放在 C::t 方法的類文件中,避免在應用層等其他文件中使用 SQL,這樣能使對象更清晰規範方便維護

官方在 source/class/table 中已經內置了很多 C::t 方法,假設在插件設計時所用的方法是官方所沒有的,而官方已創建了一個同名類文件,
這時怎麼辦?那就按上面例子所示,自己創建一個同名類文件就行了,但應用層一定要用 C::t('#插件標識符 #不帶前綴的表名') 來調用,而不是
C::t('不帶前綴的表名') 這種方式

閒暇之餘多看看 source/class/discuz 中的 discuz_database.php 和 dizcuz_table.php 這兩個重要文件,爛熟其中被 DB 封裝的常用函數的執行原理和機制,對自如運用 C::t 和加強安全認識有好處