Drupal 7 資料庫 操作(很好,很犀利)
Drupal 7 使用 PDO 連線資料庫,鑑於 PHP 6將把 PDO 做為預設資料庫連線方式,這是必須的選擇。實際上,Drupal 7之前的資料庫抽象層,和 PDO 的某些理念一致,用相同的方法操作不同型別的資料庫,減少了模組開發者的工作,也提升了程式的相容性和可移植性。引入 PDO,相對於之前的版本,資料庫介面當然有不小的變化。
最顯著的,db_fetch_object()、db_fetch_array() 這兩個最常用的函式沒用了。從前,db_query()或pager_query()之後,幾乎必然跟著上述兩個函式之一,現在,沒有了。而那些 SQL 語句中熟悉的佔位符(%d, %s, %f, %n),也沒有了。要談這兩個問題,先要了解一下大家最最熟悉的 db_query() 的改變。
在 Drupal 6 中,db_query() 接受無限個引數,第一個為 SQL 語句,後面的引數為查詢值,用以替換語句中的佔位符,大致類似於:
<?php
db_query("SELECT * FROM {system} WHERE filename = '%s'", 'system');
?>
在 db_query() 中,%d 和 %s 是不能混用的,一個是數字整型,一個是字串,%s 也必須使用單引號,防止注入。然後,Drupal 將檢查引數的合法性,最後執行語句,返回一個資源物件,用 db_fetch_object() 或 db_fetch_array() 取出結果集。
在 Drupal 7 中,db_query() 接受三個引數,第一個為 SQL 語句,第二個是一組查詢值,第三個是資料庫連線的一些設定,大致類似於:
<?php
db_query('SELECT * FROM {system} WHERE filename = ?', array('system'));
?>
在語句中的佔位符,不再需要考慮是字串或是數字,可以完全用 ? 號表示,後面的查詢值是一個索引陣列,順序必須與前面的佔位符一致,個數也必須相同。很多時候,語句較為複雜,可能需要許多佔位符,全用 ? 號,顯得混亂,可以這樣來讓程式碼更清晰:
<?php
db_query ('SELECT * FROM {system} WHERE filename = :name OR type = :theme',
array(':name' => 'system',':theme' => 'theme'));
?>
這時候,第二個引數必須是一個關聯陣列,佔位符即是陣列鍵名。這些佔位符是完全自定義的,你可以使用你喜歡的“合法”字元。這條語句中很清楚的表明,%d、%s 這些佔位符不存在了,被 ? 或自定義的佔位符取代了。為什麼呢?在 drupal 6 中,%d、%s 是用來定義傳入值的型別,然後 Drupal 資料庫層做出相應的型別檢查。而在 Drupal 7中,PDO 將檢查傳入值的合法性,不需要程式來實現,所以,那些佔位符,也光榮退休了。我覺得這一點會提升一些效能,畢竟程式來做檢查,比 PHP 底層來檢查,來得慢一些。
而第三個引數,一般很少用到,除非你想修改一些預設設定。比如,想使用一個新的資料庫連線,想返回另一種形式的結果集。Drupal 7支援多個數據連線,在 settings.php 檔案中,資料庫資訊為一個數組,鍵名即是資料庫連線的標識,如 $databases['default'] 是預設連線,這是必須的。模組開發者,可以在模組檔案中,自行定義新連線,在操作時,設定連線標識即可,例如:
<?php
$attributes = array(
'target' => 'mynewdata', //
資料庫連線標識
'fetch' => PDO::FETCH_ASSOC, //
返回的結果集型別
);
db_query('SELECT * FROM {system} WHERE filename = :name OR type
= :theme', array(':name' => 'system',':theme' => 'theme'), $attributes);
?>
PDO 預設返回一個索引和關聯陣列相結合的結果集,Drupal 7中預設設定為返回一個物件,即:PDO::FETCH_OBJ,你可以設定成 PDO::FETCH_ASSOC:返回關聯陣列,PDO::FETCH_COLUMN:返回首列。等等。所以,db_fetch_object() 和 db_fetch_array() 不需要了,在 db_query() 中直接把這一步省略了。
對比一下:
<?php
// 結果集為物件
// Drupal 6
$result = db_query('SELECT
filename, type FROM {system}');
while($o = db_fetch_object($result)){
echo $o->filename;
}
// Drupal 7if($result = db_query('SELECT filename, type FROM {system}')){
foreach($result as $o){
echo $o->filename;
}
} // 結果集為陣列
// Drupal 6
$result = db_query('SELECT filename, type FROM {system}');
while($o = db_fetch_array($result)){
echo $o['filename'];
} // Drupal 7
if($result = db_query('SELECT filename, type FROM {system}', array(), array('fetch' => PDO::FETCH_ASSOC))){
foreach($result as $o){
echo $o['filename'];
}
} // 獲取第一行
// Drupal 6
// 當然,這裡應該用 db_query_range() 來限制查詢數量為 1 條更合適
$o = db_fetch_object(db_query('SELECT filename, type FROM {system}'));
echo $o->filename; // Drupal 7
$result = db_query('SELECT filename, type FROM {system}');
echo $result->fetch()->filename; // 獲取一列
// Drupal 6
$filename = db_result(db_query_range('SELECT filename FROM {system}', 0, 1));
echo $filename; // Drupal 7
// 注意:db_query_range() 的結構和 Drupal 6 基本一致的
$result = db_query_range('SELECT filename FROM {system}', 0, 1);
echo $result->fetchColumn();
?>
如果對面向物件結構不太熟悉,看起來有點暈。實際上,對於 db_query() 返回的結果,可以使用以下方式獲取:
<?php
$result->fetch(); //
獲取一行
$result->fetchAll(); //
獲取全部,
$result->fetchObject(); //
以物件方式獲取一行
$result->fetchAssoc(); //
以關聯陣列方式獲取一行
$result->fetchColumn(); //
獲取首列
?>
因為 PDO 面向物件的特性,所以,直接使用這樣的方式也是合法的:
<?php
db_query('SELECT filename, type FROM {system}')->fetch();
db_query('SELECT filename, type FROM {system}')->fetchAssoc();
db_query_range('SELECT filename FROM {system}', 0, 1)->fetchColumn();
?>
如果使用動態查詢,這會更加更加更加的長。如果在 Drupal 7中看到很長很長很長一串的聯接,也不要太奇怪。
----------------讀了老東east的這篇後,對Drupal7的資料庫有了更深些的認識,很不錯的文章,感謝East的分享!