1. 程式人生 > >Drupal 7 資料庫 操作(很好,很犀利)

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 7
  
if($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}'01));
  echo 
$filename; // Drupal 7
  // 注意:db_query_range() 的結構和 Drupal 6 基本一致的
  
$result db_query_range('SELECT filename FROM {system}'01);
  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}'01)->fetchColumn();
?>

如果使用動態查詢,這會更加更加更加的長。如果在 Drupal 7中看到很長很長很長一串的聯接,也不要太奇怪。

----------------讀了老東east的這篇後,對Drupal7的資料庫有了更深些的認識,很不錯的文章,感謝East的分享!