2023/10/06 (新增)
2024/11/10 (更新內容)
2024/12/03 (更新內容)
在PHP裡存取資料庫有兩大類的寫法,第一種是MySQLi,MySQLi又有procedural跟object-oriented兩種寫法,第二種是PDO (PHP Data Objects),使用PDO的好處是如果連接的不是MySQL,只要更改連接的部分,其他的部分都不用更動,算是比較彈性。缺點是PDO的語法只提供物件導向的寫法。
在資料處理的部分,其實PDO有很多呈現資料的方式,一般常用的是以PHP特有的Associative Array的方式呈現,也可以採用物件(類別)的方式呈現,採用物件的話,還要先寫類別,會比較麻煩,所以,通常採用Associative Array。但當我們必須去處理欄位內容時,就必須透過類別來處理,。
在語法上PDO跟mysqli的物件導向與法相近,我們以兩個例子簡單的比較三種語法:
mysqli procedural
$conn = mysqli_connect($servername, $dbUsername, $dbPassword, $dbname);
mysqli object-oriented,因為是物件導向,要先從mysqil類別中產生一個connection,語法跟多數的程式語言類似。除此了需要產生物件之外,參數都一樣。
$conn = new mysqli($servername, $username, $password, $dbname);
因為PDO可以連接不同的資料庫,所以,呼叫方式稍微不同。
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
以讀取資料為例,procedural的寫法$conn就會是mysqli_query的參數之一:
$sql = "SELECT id, firstname, lastname FROM MyGuests";
$result = mysqli_query($conn, $sql);
object-oriented的寫法$conn就是個物件,所有的方法都是以物件去呼叫,在PHP裡,「.」被用來表示字串相加,所以,呼叫的方式跟其他語言就不一樣,使用的是「->」:
$sql = "SELECT id, firstname, lastname FROM MyGuests";
$result = $conn->query($sql);
PDO的語法就差不多
$sql = "SELECT id, firstname, lastname FROM MyGuests";
$result = $conn->query($sql);
其中「PDO::ATTR_ERRMODE」及「PDO::ERRMODE_EXCEPTION」是使用PDO類別裡的類別常數,在PHP裡使用類別常數是利用「::」(詳參: Class Constants)。
可利用setAttribute()進行設定,setAttribute()接受兩個參數 (詳參:PDO::setAttribute) ,第一個參數是指定要設定的參數類型,例如:「PDO::ATTR_ERRORMODE」,也就是指接下來要設定錯誤的處理方式,換句話說就是要第二個參數將會是錯誤的處理方式(詳參: Predefined Constants )。 在PHP裡取得類別常數是利用「::」(詳參: Class Constants)。第二個參數就是設定的值,例如:錯誤的處理方式,設為「PDO::ERRMODE_EXCEPTION」是要求PDO在有錯誤時會回傳Exception,在PHP裡,如同Java,是可以利用try.. catch處理PDO回傳的錯誤 (詳參: Errors and error handling 、Exceptions)。
setAttribute()還有不同的屬性可以設定,請詳參:PDO::setAttribute。
<?php
$servername = "localhost";
$dbname = "practice";
$username = "root";
$password = "12345678";
try {
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
// set the PDO error mode to exception
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo "Connected successfully";
}
catch(PDOException $e)
{
echo "Connection failed: " . $e->getMessage();
}
?>
取得資料時,可利用fetchAll(),並利用參數指定取得的模式(如:PDO::FETCH_ASSOC),也可以利用setAttribute()設定取得模式。因為我們沒有教類別的使用,所以,以下都以Associative Array為例。
當資料龐大時,可能不想一次取得所有資料,也可以逐筆取得
<?php
require 'db.php';
$sql="select * from job";
$stmt = $conn->prepare($sql);
$stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
<table width='85%' style='float:center'>
<tr style='text-align:center'>
<td>求才廠商</td>
<td>求才內容</td>
<td>日期</td>
</tr>
<?php
foreach($rows as $job){ ?>
<tr style='text-align:center'>
<td><?=$job["company"]?></td>
<td><?=$job["content"]?></td>
<td><?=$job["pdate"]?></td>
</tr>
<?php
}
$conn = null;
?>
</table>
PDO可以使用「?」
$sql="insert into job (company, content, pdate) values (?, ?, ?)";
$stmt = $conn->prepare($sql);
$result = $stmt->execute([$_POST["company"], $_POST["content"],$_POST["pdate"]]);
也可以設定參數名稱,並利用bindValue()去綁定內容,bindValue()可指定資料型態
$stmt->bindValue(':company', $_POST["company"], PDO::PARAM_STR);
$sql="insert into job (company, content, pdate) values (:company, :content, :pdate)";
$stmt = $conn->prepare($sql);
$stmt->bindValue(':company', $_POST["company"]);
$stmt->bindValue(':content', $_POST["content"]);
$stmt->bindValue(':pdate', $_POST["pdate"]);
$result = $stmt->execute();
很多同學會問: PDO沒辦法一次bind多個變數嗎? 可以的!!
PDO提供更簡短的寫法,如果POST的欄位跟資料表的欄位名稱是一致的話,可以直接利用execute,因為execute會接受一個陣列,並把陣列裡的內容跟參數做對應 (詳參: INSERT query using PDO)。
// insert data
$sql="insert into job (company, content, pdate) values (:company, :content, :pdate)";
$stmt = $conn->prepare($sql);
$result = $stmt->execute($_POST);
PDO也可以使用bindParam(),與bindValue()不同的是,bindParam()一定要綁變數,不可以直接綁數字或字串。主要差別在於bindParam()是在execute()時才會去取值,而bindValue()則是在bindValue()時就直接取值了~ 所以,當我們要執行批次的新增或修改,bindParam()只要綁定一次。
// ERROR!!!
$stmt->bindParam(':searchtxt', "Ben"]);
$sql="select * from job where company = :searchtxt";
$stmt = $conn->prepare($sql);
$stmt->bindParam(':searchtxt', $_POST["searchtxt"]);
$stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
// updte data
$sql="update job set company=:company, content=:content, pdate=:pdate where postid=:postid";
$stmt = $conn->prepare($sql);
$result = $stmt->execute($_POST);
$sql = "DELETE FROM job WHERE postid=:postid";
$stmt = $conn->prepare($sql);
$stmt->execute(["postid"=>$postid]);