許多PHP程序員學(xué)習(xí)過(guò)如歌使用MySQL或MySQL擴(kuò)展來(lái)訪問(wèn)數(shù)據(jù)庫(kù). 不過(guò),自PHP 5.1版本以來(lái),一個(gè)更好的解決方案出現(xiàn)了. PHP Data Objects (PDO) 提供了讓你更有{productive}的準(zhǔn)備{statements},處理對(duì)象的方法.
“PDO – PHP Data Objects – is a database access layer providing a uniform method of access to multiple databases.”
它不受數(shù)據(jù)庫(kù)特定語(yǔ)法限制, 但它可以讓切換數(shù)據(jù)庫(kù)和平臺(tái)的過(guò)程更無(wú)痛,更簡(jiǎn)潔的切換數(shù)據(jù)庫(kù)連接字符串.
這個(gè)教程并是一個(gè)完全的SQL入門. 它主要是為了幫助那些已經(jīng)在使用MySQL或MySQLi擴(kuò)展的人們過(guò)渡到更加強(qiáng)大、兼容性更好的PDO.
數(shù)據(jù)庫(kù)支持
這個(gè)擴(kuò)展能支持任何為PDO設(shè)計(jì)了驅(qū)動(dòng)的數(shù)據(jù)庫(kù). 在寫這篇文章的時(shí)候,以下數(shù)據(jù)庫(kù)已經(jīng)被支持:
所有這些驅(qū)動(dòng)都沒(méi)有被您的系統(tǒng)預(yù)裝,這里有一種快速的方式來(lái)找到您需要的驅(qū)動(dòng):
print_r(PDO::getAvailableDrivers());
不同的數(shù)據(jù)庫(kù)可能在連接方法上有那么一點(diǎn)點(diǎn)的不同. 下面,我們將介紹幾種常見(jiàn)的數(shù)據(jù)庫(kù)的連接方法. 你將會(huì)注意到前三種看起來(lái)差不多, 不過(guò)像SQLite之類的語(yǔ)言就有他自己獨(dú)特的語(yǔ)法.
請(qǐng)注意try/catch代碼塊 – 您應(yīng)該始終將您 PDO 的操作封裝在一個(gè) try/catch 代碼塊內(nèi)并使用異常機(jī)制 .通常你只會(huì)使用單個(gè)連接 – 下面將為您介紹它的語(yǔ)法.
下文中出現(xiàn)的 $DBH 意思是 ‘database handle’.
你可以通過(guò)把handle設(shè)置為null來(lái)關(guān)閉任何數(shù)據(jù)庫(kù)連接.
# close the connection
$DBH = null;
你可以從 PHP.net 獲取更多關(guān)于特點(diǎn)數(shù)據(jù)庫(kù)的選項(xiàng)和連接字串(connection strings)的信息
PDO 可以使用異常(Exceptions)來(lái)處理錯(cuò)誤,這意味你需要把{處理PDO的}包括在一個(gè)try/catch代碼塊. 你也可以通過(guò)設(shè)置錯(cuò)誤模式(error mode attribute)強(qiáng)制PDO在您最近創(chuàng)建的數(shù)據(jù)庫(kù)連接上使用這三種錯(cuò)誤模式中的一種. 以下提供了語(yǔ)法:
$DBH->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT );
$DBH->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING );
$DBH->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
不過(guò)不管您設(shè)置什么錯(cuò)誤模式, 錯(cuò)誤的連接總會(huì)產(chǎn)生一個(gè)異常, 所以您應(yīng)該在創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)時(shí)包含一個(gè)try/catch代碼塊.
PDO::ERRMODE_SILENT
這是默認(rèn)的錯(cuò)誤模式. 如果您使用了這種錯(cuò)誤模式, 你將像您用mysql或mysqli擴(kuò)展的時(shí)候那樣自己檢查錯(cuò)誤. 這里還有兩種更理想的符合[[DRY programming]]思想的方法.
PDO::ERRMODE_WARNING
這種模式將會(huì)發(fā)出(issue)一個(gè)標(biāo)準(zhǔn)的PHP warning,然后繼續(xù)執(zhí)行程序. 這種方法在調(diào)試時(shí)會(huì)很有用.
PDO::ERRMODE_EXCEPTION
這也許是人們?cè)诖蠖鄶?shù)情況下希望使用的模式. 它拋出(fire)一個(gè)異常, 允許你優(yōu)雅的處理錯(cuò)誤并且隱藏那些可能會(huì)導(dǎo)致安全風(fēng)險(xiǎn)的數(shù)據(jù). 這里是一個(gè)處理異常的實(shí)例:
上面是一個(gè)在select statement中的內(nèi)部錯(cuò)誤; 這將會(huì)引發(fā)一個(gè)異常. 這段異常處理代碼將會(huì)把錯(cuò)誤詳情發(fā)送到一個(gè)日志文件中, 然后顯示一個(gè)友好的(當(dāng)然,友不友好隨你便)消息給用戶.
插入新數(shù)據(jù)、或更新一個(gè)已經(jīng)存在的數(shù)據(jù),是最常見(jiàn)的數(shù)據(jù)庫(kù)操作之一. PDO提供了一種[[normally a two-step process]]. 本節(jié)中介紹的所有內(nèi)容同樣適用于 UPDATE 和 INSERT 操作.
下面是一個(gè)最基本的插入的例子:
# STH means “Statement Handle”
$STH = $DBH->prepare(“INSERT INTO folks ( first_name ) values ( ‘Cathy’ )”);
$STH->execute();
您也可以直接使用exec()方法完成相同的操作(PS:使用exec()方法可以減少一個(gè)調(diào)用). 在大多數(shù)情況下,您可能會(huì)多次調(diào)用這個(gè)方法, 所以呢, 您可以享受到prepared statements帶來(lái)的好處. 甚至如果您只想調(diào)用它一次, 使用prepared statements will 也會(huì)幫您擋住 SQL injection 攻擊.
Prepared Statements
使用 prepared statements 將幫助您防止 SQL injection 的危險(xiǎn).
Prepared statement的語(yǔ)句是只需要發(fā)送數(shù)據(jù)到服務(wù)器的預(yù)編譯 SQL 語(yǔ)句, 它具有自動(dòng)處理數(shù)據(jù)以免受 SQL injection 攻擊的優(yōu)點(diǎn)。
您可以通過(guò)在您的SQL語(yǔ)句中包含占位符來(lái)使用 prepared statement . 這里有三個(gè)例子: 一個(gè)沒(méi)有占位符的, 一個(gè)有未命名占位符(Unnamed Placeholders)的, 和一個(gè)有命名占位符(Named Placeholders)的.
您可能想避免使用第一種方法; 下面為您提供了它們直接的比較. 選擇未命名占位符或命名占位符將會(huì)影響您如何為這些語(yǔ)句設(shè)置數(shù)據(jù).
未命名占位符(Unnamed Placeholders)
只需兩步!首先,我們?yōu)椴煌恼嘉环≒laceholder)綁定變量 (lines 2-4). 然后,我們?yōu)槟切┱嘉环≒laceholder)賦值然后執(zhí)行查詢. 要想發(fā)送另外的一組數(shù)據(jù),只需要改變那些變量的值,然后再執(zhí)行即可.
(譯注: 原文在第一步與第二布均使用了assign來(lái)描述過(guò)程)
這個(gè)使用很多參數(shù)的方法似乎有點(diǎn)麻煩?如果您的數(shù)據(jù)存儲(chǔ)在數(shù)組中,有一個(gè)簡(jiǎn)單的方法:
這很簡(jiǎn)單,不是嗎?
在數(shù)組中的數(shù)據(jù)等同于占位符。 $data[0]對(duì)應(yīng)第一個(gè)占位符,$data[1]第二個(gè),依此類推,但如果您的數(shù)組索引并未排序,這將無(wú)法正常工作,您將需要重新索引這個(gè)數(shù)組.
命名占位符(Named Placeholders)
您可能已經(jīng)猜到語(yǔ)法了,下面給出了一個(gè)例子:
您也可以在這里使用一個(gè)快捷方式,但它可以和關(guān)聯(lián)數(shù)組一起使用.
你的數(shù)組中的鍵不需要以一個(gè)冒號(hào)開(kāi)始,但是必須符合指定的占位符。如果你有一個(gè)二維數(shù)組(就是數(shù)組中的數(shù)組),您可以遍歷它們,只需調(diào)用執(zhí)行的每個(gè)數(shù)據(jù)的數(shù)組。
另一個(gè)命名占位符不錯(cuò)的特點(diǎn)是直接可以插入對(duì)象到您的數(shù)據(jù)庫(kù),如果命名的屬性匹配字段的話.下面是一個(gè)例子對(duì)象:
在執(zhí)行中,對(duì)象被轉(zhuǎn)換為一個(gè)數(shù)組.對(duì)象的屬性被視為數(shù)組中的一個(gè)鍵. By casting the object to an array in the execute, the properties are treated as array keys.
數(shù)據(jù)通過(guò)fetch()方法獲得, {一種應(yīng)用于陳述式句柄的方法}. 在使用fetch之間, 您最好告訴PDO您喜歡取得數(shù)據(jù)的樣子. 您有以下幾個(gè)選擇:
在現(xiàn)實(shí)中,大多數(shù)情況下會(huì)使用以下三種: FETCH_ASSOC, FETCH_CLASS, FETCH_OBJ. 您需要使用以下語(yǔ)法設(shè)置獲取類型:
$STH->setFetchMode(PDO::FETCH_ASSOC);
您也可以直接在fetch()方法中設(shè)置獲取模式.
FETCH_ASSOC
這種模式創(chuàng)建一個(gè)按列名索引的關(guān)聯(lián)數(shù)組.這應(yīng)該會(huì)讓用過(guò)MySQL/MySQLi擴(kuò)展的人感到親切.這里有一個(gè)使用這種方法選擇數(shù)據(jù)的例子.
這個(gè) while 循環(huán)將在獲取完所有數(shù)據(jù)后停止.{The while loop will continue to go through the result set one row at a time until complete.}
FETCH_OBJ
這種模式為每一行數(shù)據(jù)創(chuàng)建一個(gè)標(biāo)準(zhǔn)類,下面是一個(gè)例子:
FETCH_CLASS
您的對(duì)象的屬性應(yīng)該在constructor被調(diào)用前設(shè)置!這一點(diǎn)很重要!
這種模式允許你直接將獲取的數(shù)據(jù)發(fā)送到您選擇的類中.當(dāng)您使用FETCH_CLASS時(shí),您的對(duì)象的屬性應(yīng)該在constructor被調(diào)用前設(shè)置。讀一遍,它是重要的。如果屬性相匹配的列名不存在,這些屬性將被創(chuàng)建,(公共)為您。
這意味著如果你需要轉(zhuǎn)換后出來(lái)的數(shù)據(jù),它可以通過(guò)你的對(duì)象自動(dòng)為轉(zhuǎn)換.
舉個(gè)列子,假設(shè)的情況下該地址必須為特定格式,我們可以通過(guò)constructor上做到這一點(diǎn),下面是一個(gè)例子:
OK,再讓我們看看效果如何?
如果地址是,‘5 Rosebud,’ 您將會(huì)在輸出中看到 ‘5 Rxxxxxx’. 當(dāng)然,可能有些情況下,您希望在constructor函數(shù)在數(shù)據(jù)被賦值之前調(diào)用.PDO也可以做到~
現(xiàn)在,當(dāng)你使用這個(gè)模式(PDO::FETCH_PROPS_LATE)的地址不會(huì)被遮,constructor會(huì)被首先調(diào)用然后再賦值.
最后,如果你真的需要,你可以在使用PDO獲取數(shù)據(jù)到對(duì)象時(shí),將參數(shù)傳遞給構(gòu)造函數(shù):
如果你需要傳遞不同的數(shù)據(jù)到每個(gè)對(duì)象的構(gòu)造函數(shù),你可以設(shè)置在fetch方法內(nèi)設(shè)置模式法模式:
雖然 PDO 并沒(méi)有面面俱到的(這擴(kuò)展可不小!), 這里仍還還有一些您想知道的方法.
$DBH->lastInsertId();
lastInsertId()方法始終調(diào)用數(shù)據(jù)庫(kù)句柄,而不是表達(dá)式的句柄,并且會(huì)返回該數(shù)據(jù)庫(kù)連接上一次插入語(yǔ)句的自增ID.
$DBH->exec(‘DELETE FROM folks WHERE 1′);
$DBH->exec(“SET time_zone = ‘-8:00′”);
exec()方法用于那些不能返回?cái)?shù)據(jù)或不影響行的操作. 上面是兩種調(diào)用exec()方法的例子.
$safe = $DBH->quote($unsafe);
quote() 方法將字符轉(zhuǎn)義為安全的字符以便在查詢中使用. 如果您不使用已經(jīng)準(zhǔn)備號(hào)的語(yǔ)句,您可以用此方法<<*>>。
$rows_affected = $STH->rowCount();
rowCount() 方法返回一個(gè)表明被一個(gè)操作影響的行數(shù)的整數(shù)(簡(jiǎn)直是廢話,難不成還是浮點(diǎn)數(shù)?). 更具這個(gè)錯(cuò)誤報(bào)告(http://bugs.php.net/40822) ,在最近的一個(gè)PDO版本上這個(gè)方法不能夠很好的與SELECT語(yǔ)句工作. 如果您遇到了這個(gè)問(wèn)題而不想升級(jí)PHP的話, 你可以用以下的方法來(lái)替代它:
我希望這篇文章能幫助您從mysql和mysqli擴(kuò)展遷移至PDO.您有啥想法?現(xiàn)在想遷移到PDO么?
英文原文:http://net.tutsplus.com/tutorials/php/why-you-should-be-using-phps-pdo-for-database-access/
聯(lián)系客服