一、 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 和加強安全認識有好處