文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>PEAR::DB

PEAR::DB

时间:2007-06-27  来源:liuxingyuyuni


對於編寫網頁程式, PHP 確實是一個非常不錯的語言,簡單易學易寫,速度又快。 不過在編寫較複雜的程式時,就未能像 Perl 及 Java 等就有很強大的函數庫支援 。 其實,PHP 不是沒有函數庫,但一向都散遍網絡各地,缺乏一個中央收集庫,尋找較因難,又經常重複同樣功能。另外缺乏統一的編寫標準,令整合使用上有不少問題。PEAR 的出現就是為了解決以上問題。

PEAR 的全寫為 PHP Extension and Application Repository ,其作用和 Perl 的 CPAN 差不多。這計劃最初由 Stig S. Bakken 於 1999 年尾發起,亦在 PHP4 發佈 beta 4 版時正式收錄在 PHP4 中。
PEAR::DB - 資料庫存取套件
PEAR 中最常用的套件 (package) 恐怕是 PEAR::DB 。 PEAR::DB 作用和 Perl 的 DBI 及 Java 的 JDBC 差不多,讓你可以用相同的介面去取存不同的資料庫管理系統 (DBMS) 。 PHP 本身雖有提供存取各 DBMS 的函數,但這些函數只是由有關的 C API 直接轉過來,如 mysql_query 及 pg_exec 等。同樣的功,不同的 DBMS 有不同的函數,有不同的使用方法。如果不幸你需要轉換程式使用另一個 DBMS ,那就是一件非常頭痛的事。學習使用另一個 DBMS 要花時間,最恐怖還是將整個程式來個大翻新。為了令程式可以使用不同的資料庫,很多開發者都會編寫一些函數庫或類別庫來處理對資料庫的存取。
query('SELECT id, name FROM test_table ORDER BY id');
if ( $dbh->numRows($result) > 0 ) {
    echo "IDName";
    while ( $data = $result->fetchRow() ) {
        echo "$data[0]$data[1]";
    }
    echo "
";
} else {
    echo "Ok;
";
}
?>
上面的程式很簡單示範如何使用 PEAR::DB。很多朋友都會留意到基本步驟和平常的資料庫程式沒有多大分別。首先用 DB::connect 連接資料庫, $db->query 對資料庫發出查詢要求, $db->numRows 取得查詢結果有幾多筆記錄, $result->fetchRow() 則幫我們一筆一筆地遂次傳回查詢結果中的記錄。無論那個 DBMS ,方法都一樣。如果要轉 DBMS ,改改 DB::connect 的參數就可以了。
PEAR::DB 的架構是每一個 DBMS 都有自己的一個資料庫驅動類別 (如 DB_mysql 及 DB_pgsql 等) ,包含了存取 DBMS 實質需要的程式碼 ,它們全部都衍生自類別 DB_common 。主類別 DB 則包含了整個套件一些公用函數, DB_Error 儲存有關錯誤資料, DB_result 處理 SELECT 查詢的結果。
連接資料庫
前面的例子已顯示連接資料庫的工作是由 DB:connect 來達成。它會經由參數得知要連接的是那個 DBMS ,載入需要的資料庫驅動類別並向資料庫伺服器發出連接要求,成功就傳回載有連接資料庫資料的物件。
要連接資料庫,當然一定要知道要連接那台資料庫伺服器的資料庫,連接帳戶及密碼等。 這方面我們要用 DSN (Data Source Name) 來告知 DB:connect 。 DSN 的格式如下:
phptype(dbsyntax)://username:password@protocol+hostspec/database
phptype:
DBMS 的類型 (如 mysql 及 oracle 等)
dbsyntax:
資料庫使用那種 SQL 語法
protocol:
連接用的通訊協定 (如 tcp 及 unix 等)
hostspec:
連接的電腦 (hostname[:post])
database:
要連接的資料庫名稱
username:
連接用的帳戶名稱
password:
連接用的帳戶密碼
例如要連接電腦 db.foo.com 中的 MySQL 伺服器裡的資料庫 test ,就可以用:
$dbh = DB::connect('mysql://voidoo:[email protected]/test');
使用 unix socket 連接所在電腦中的 PostgreSQL 伺服器,則用:
$dbh = DB::connect('pgsql://hychan:AlsoSecret@unix+localhost/hklug');
除了用整串 DSN ,你亦可以把 DSN 的參數放入陣列中:
$dsn = array(
    'phptype' => 'mysql',
    'hostspec' => 'localhost',
    'username' => 'xychen',
    'password' => 'AnotherSecret'
}
$dbh = DB::connect($dsn);
DB::connect 會根據 DSN 載入有關 DBMS 的類別。 PHP 4.0.6 中的 PEAR 已支援下列 DBMS :

  • InterBase (ibase)
  • Informix (ifx)
  • mSQL (msql)
  • mssql (MS SQL)
  • MySQL (mysql)
  • Oracle 7/8/8i (oci8)
  • ODBC (odbc)
  • PostgreSQL (pgsql)
  • SyBase (sybase)

另外,除了 DSN ,你亦可以設定這個連接的一些選項:
$dbh = DB::connect($dsn, array('persistent' => true));
不同的 DBMS 會有不同的選項,而最基本所有都有兩個選項:
persistent
是否 persistent connection , 預設為否。
optimize
可以是 'performance' 或 'portability', 從字面上可以知道這個選項可以控制查詢時則重速度還是兼容性。 暫時來說,這選項只在 MySQL 、 FrontBase 及 Oracle 中有作用。 選 'portability' 在 MySQL 及 FrontBase 中會自動修改 DELETE 命令,令 $dbh->affectedRows() 可以傳回刪除了多少筆記錄。在 Oracle 中則會替你模擬 $dbh->numRows() 的功能。
執行 SQL 命令
大家都應該知道什麼是 SQL,我也不想花時間在這類基本慨念問題,有興趣的可以到 http://www.onlamp.com/mysql/onlamp/general/mysql.csp ,裡面一些 SQL 的淺介。
SELECT 命令可算是 SQL 中最重要的命令,其他命令如 INSERT 、 UPDATE 和 DELETE 主要都是用作修改資料庫上的資料,傳回結果也只是成功或失敗兩種。而 SELECT 命令就會傳回查詢得到的資料,而這些資料可能佔用很大的資源,所以處理兩類命令亦有點分別。
query 及 simpleQuery
前面的例子都顯示了要求資料庫執行 SQL 命令的動作是由 $dbh->query() 去做的,但其實還有個 $dbh->simpleQuery() 。事實上, $dbh->query() 本身都是透過 $dbh->simpleQuery() 去向資料庫發出執行 SQL 的要求。 $dbh->simpleQuery() 執行成功,如執行的 SELECT 命令則會傳回有關資料庫的 result handle ,其他則傳回 DB_OK 。 $dbh->query 的作用是把 simpleQuery() 傳回的 result handle 變成 DB_result 物件。在一般情況下,我都建議大家用 $dbh->query 。
$dbh->quoteString($str)
quoteString 的作用是將和 addslashes 一樣,處理 $str 中引數 (', ") 這類可能會做成 SQL 命令語法錯誤的字元。如 $dbh->query("SELECT * FROM posts WHERE subj = '$subj'") 中, $subj 的值如果是 "peter's box" , 中間含單引號,整個 SQL 命令就變成 "SELECT * FROM posts WHERE subj = 'peter's box'" ,做成語法錯誤。如果你事前經 quoteString 處理,問題就可以解法了:
$subj = $dbh->quoteString($subj);
$subj 如在 PostgreSQL 或 MySQL 就會變成 "peter's box" ,在 Oracle 則變成 "peter''s box" 。
要留意現時 PEAR 的 cvs 中,新增了一個方法 quote ,和 quoteString 的分別是 quote 還會在字串的前後加單引號。
prepare 、 execute 及 executeMultiple
其實有些資料庫管埋系統有提供預先編譯 SQL 命令的功能,可以加快查詢的速度。
$sql = $dbh->prepare("INSERT INTO test_table (name) VALUES('test')");
for( $i = 0; $i execute($sql);
}
以上例子和重覆執行十次同一句 INSERT 命令的結果一樣,但在一些資料庫管埋系統,因為 INSERT 命令已預先被編譯,所以速度會較快。被編譯的 SQL 命令亦可以有參數。
$data = array('mary', 'peter', 'john', 'robert');
$sql = $dbh->prepare("INSERT INTO test_table (id, name) VALUES(?, ?)");
for( $i = 0; $i execute($sql, array( $i, $name) );
}
$data = array(
  array('mary', '[email protected]'),
  array('peter', '[email protected]'),
  array('john', '[email protected]'),
  array('robert', '[email protected]')
);
$sql = $dbh->prepare("INSERT INTO test_table (name, mail) VALUES(?, ?)");
$dbh->executeMultiple($sql, $data);
prepare 等會自動幫你將參數用 quoteString 處理,所以你不用擔心參數中的引號。但要留意 ? 只可以是實際的資料,你不可以以 table 名或欄名作為參數,以以下的用法都是 錯誤的:
SELECT ?, name FROM test_table
DELETE FROM ? WHERE id = ?
現時只有 InterBase 及 Oracle 支援 prepare 等方法,支有支援的則由 PEAR::DB 模擬出來。
處理查詢結果
$result->fetchRow 及 $dbh->setFetchMode
第一個例子已告訴了大家可以用 $result->fetchRow 去讀取查詢的結果。用 PHP 寫過資料庫程式的朋友都知道 PHP 提供了三種方式來傳回查詢: *_fetch_row 、 *_fetch_array 及 *_fetch_object 。當然 fetchRow 也不會漏了這功能。 fetchRow 的第一個參數就是所謂讀取模式 (fetch mode, 結果以那種方式傳回) ,可以有下列值:

  • DB_FETCHMODE_ORDERED (預設值)
  • DB_FETCHMODE_ASSOC
  • DB_FETCHMODE_OBJECT

如沒有設定讀取模式,預設就是 DB_FETCHMODE_ORDERED 。這模式 在例一已示範過了,只是把傳回的結果存放在一以數字作索引的陣列的中。前後次序是根據 SELECT 命令中欄名的次序。模式 DB_FETCHMODE_ASSOC 則存放在以欄名作索引的陣列,例如:
$result = $dbh->query('SELECT id, name, mail FROM test_table');
while ( $row = $result->fetchRow(DB_FETCHMODE_ASSOC)) {
    echo "ID: $row['id']
";
    echo "Name: $row['name']
";
    echo "E-mail: $row['mail']
";
}
模式 DB_FETCHMODE_OBJECT 比較複雜,你最好先定義一個類別。這個類別必需要有一個只用一個陣列作參數的 constructor ,而 constructor 要從陣列中的值設回屬性,如下:
class TestUser {
    var $id, $name, $mail;
    function TestUser($attr = null) {
        if ( is_array($attr) ) {
            $this->id = $attr['id'];
            $this->name = $attr['name'];
            $this->mail = $attr['mail'];
        }
    }
    function toString() {
        $res = "TestUser{
  ID: $this->id
";
        $res .= "  Name: $this->name
";
        $res .= "  Mail: $this->mail
}
";
        return $res;
    }
}
有了這個類別,我們就可以用 DB_FETCHMODE_OBJECT 去讀取資料:
$dbh->setFetchMode(DB_FETCHMODE_OBJECT, 'TestUser');
$result = $dbh->query('SELECT id, name, mail FROM test_table');
while ( $row = $result->fetchRow()) {
    echo nl2br($row->toString());
}
上面的例子也首次使用了 setFetchMode 這個方法。很多人應已猜到這方法是用來設定預設的讀取模式,而如果設定的模式是 DB_FETCHMODE_OBJECT ,你就可以用第二個參數設定 fetchRow 時傳回物件的類別,如上例中的 TestUser 。沒有設定類別的話,fetchRow 會傳回類別為 DB_row 的物件。
$dbh->getOne($query, $params = array())
getOne 會傳回查詢結果中第一筆記錄的第一個欄的值。
$numOfRecord = $dbh->getOne('SELECT count(*) FROM test_table');
$dbh->getRow($query, $fetchmode, $params)
getRow 會傳回查詢結果的第一筆記錄。
$result = $dbh->getRow('SELECT * FROM test_table WHERE id = 4',
    DB_FETCHMODE_ASSOC);
if ( DB::isError($result) ) {
   echo "Error: " . $result->getMessage();
   exit(1);
}
echo "ID: $result['id']
";
echo "Name: $result['name']
";
$dbh->getCol($query, $col = 0, $params)
有 getRow 自然有 getCol ,作用為何也不必多說。參數 col 就是用來指定要那一欄,可以是數目字 (零代表 SELECT 命令中的第一個欄) ,也可以是欄名。不過說實,我暫時也想不到有什麼理由需要這個參數。
$result = $dbh->getCol('SELECT name FROM test_table');
if ( DB::isError($result) ) {
   echo "Error: " . $result->getMessage();
   exit(1);
}
echo "Name: " . join(', ', $result) . "
";
$dbh->getAssoc($query, $force_array)
getAssoc 會將查詢的所有結果放入以第一欄為索引的陣列。例如 getAssoc('SELECT id, text FROM mydate') 的結果會是:
  array (
    '1' => 'one',
    '2' => 'two',
    '3' => 'three'
  )
getAssoc('SELECT id, text, date FROM mydate')的結果則是:
  array (
    '1' => array('one', '944'),
    '2' => array('two', '944'),
    '3' => array('three', '944')
  )
$dbh->getAll($query, $params, $fetchmode)
從名字都可以看出這個數可以一次過把所有查詢的結果存回來 ,如 getAll('SELECT id, text FROM mydate', null, DB_FETCHMODE_ORDERED) 的結果會以下:
  array(
    array('1', 'one'),
    array('2', 'two'),
    array('3', 'three')
  )
而 getAll('SELECT id, text FROM mydate', null, DB_FETCHMODE_ASSOC) 的結果則會以下:
  array(
    array( 'id' => '1', 'text' => 'one'),
    array( 'id' => '2', 'text' => 'two'),
    array( 'id' => '3', 'text' => 'three')
  )
$dbh->limitQuery($query, $from, $count)
首先要聲明這個方法也只是剛在 10 月 31 日才加入 PEAR 的 cvs 中,你手上的 PEAR 應該未支援。而使用方法可能還會有所改動,而且在某 DBMS 的支援還可能會有很多問題 (Oracle 及 InterBase 要小心) 。不過這方法蠻有用,所以在些率先一提。
$dbh->limitQuery 的作用是只讀取查詢中的部份結果,這對編寫網站程式很有作用。
setFetchMode(DB_FETCHMODE_ASSOC);
$sql = 'SELECT subj, author, posttime FROM posts ORDER BY posttime DESC';
$result = $dbh->limitQuery($sql, $p * 10, 10);
?>
SubjectAuthorTimeresultRow() ) : ?>
  
Prev
|
Next
Sequence
現在很多 DBMS 都有支援 sequence , 方便產生資料庫的主鍵 (Primary Key) ,不過使用方法都有不同, MySQL 甚至用自動增值 (Auto_Increment) 的屬性處理類始 sequence 的應用。不一的使用介面自然令程式的可移殖性大減。 PEAR::DB 就提供了一堆方法去處理這個問題。
PEAR::DB 用 $dbh->nextId 來統一運用 sequence 的介面。執行 nextId 會俾回將 sequence 的值遞增一並值回其值,如果 sequence 不存在, nextId 就會自動建立 sequence ,如下:
$name = 'Maddog';
$id = $dbh->nextId('test_table');
$dbh->query("INSERT INTO test_table (id, name) VALUES($id, '$name');
如你不想 nextId 自動建立 sequence 你可以用 $dbh->nextId($seqName, false) 。 PEAR::DB 亦提供 createSequence 和 dropSequence 來建立或刪除一 sequence ,但在一般情況下,你都不會用得著他們。
其他方法
$dbh->affectedRows()
傳回對上個 INSERT/UPDATE/DELETE 查詢影響了多少個記錄。
$result->numRows()
傳回查詢結果中有幾多筆記錄
$result->numCols()
傳回查詢結果中每筆記錄有幾多欄
$result->tableInfo()
傳回杳詢結果中各欄的資料
$result->free()
釋放查詢結果所佔有的系統資源
$dbh->autoCommit(true/false)
設定是否使用 transaction
$dbh->commit()
完成當前的 transaction
$dbh->rollback()
取消當前的 transaction
錯誤處理
前面所有函數或方法都只提到成功會傳回什麼,但失敗了又怎樣呢? 其實 PEAR::DB 上所有函數或方法在失敗時都個傳回一個類別為 DB_Error 或 DB_Warning (事實上暫時只有傳回 DB_Error) 的物件,而這個物件就記錄了失敗的原因及有關資料。
錯誤的最常見處理方法是顯示錯誤訊息並終止程式,如下:
$dbh = DB::connect('mysql://voidoo:@localhost/test_db');
if ( DB::isError($dbh) ) {
    echo $dbh->getMessage();
    exit(1);
}
$result = $dbh->query("INSERT INTO test_table (id, name) VALUES(5, 'Shell')");
if ( DB::isError($result) ) {
    echo $result->getMessage();
    exit(1);
}
如你要顯示發生問題時是執行那個 SQL 命令,可將上面的 getMessage 轉成 getDebugInfo 。
其他參考資料

  • PEAR Offical Site
    http://pear.php.net/
  • PHP Manual V. PEAR
    http://www.php.net/manual/en/pear.php
  • Quick Start Guide to Pear DB
    http://vulcanonet.com/soft/?pack=pear_tut
  • Best Practices: Database Abstraction - PhpBuilder
    http://www.phpbuilder.com/columns/allan20010115.php3
  • PEAR Documentation and Tutorials - PHP Everywhere
    http://php.weblogs.com/php_pear_tutorials


相关阅读 更多 +
排行榜 更多 +
jojo的奇妙冒险手机版下载

jojo的奇妙冒险手机版下载

飞行射击 下载
雪糕工厂 v9.87.13.02 安卓版

雪糕工厂 v9.87.13.02 安卓版

休闲益智 下载
雪糕工厂 v9.87.13.02 安卓版

雪糕工厂 v9.87.13.02 安卓版

休闲益智 下载