PHP: PDO กับฐานข้อมูล


หน้าแรก PHP MySQL เกร็ดความรู้ PHP: PDO กับฐานข้อมูล
ในการใช้ PHP ทำงานร่วมกับฐานข้อมูล จำเป็นต้องรู้ภาษา SQL เสียก่อน และต้องรู้ด้วยว่า ฐานข้อมูลที่ต้องทำงานด้วยนั้นเป็นระบบไหน เพราะ PHP มีคำสั่งเฉพาะสำหรับฐานข้อมูลแต่ละระบบแยกกันอยู่

แต่เมื่อมีเทคโนโลยีมากขึ้นระบบฐานข้อมูลมีความหลากหลายมากขึ้น ความคล่องตัวในการย้ายฐานข้อมูลจากระบบหนึ่งไปยังอีกระบบหนึ่งก็ยุ่งยากขึ้น ทาง PHP จึงสร้าง extension ชื่อ PDO (PHP Data Objects) ขึ้นมาเพื่อเป็นตัวกลางในการจัดการฐานข้อมูล โดยโปรแกรมเมอร์แทบไม่ต้องสนใจว่า ระบบฐานข้อมูลที่จะทำงานร่วมกันเป็นแบบไหน

การเชื่อมต่อกับระบบฐานข้อมูลผ่าน PDO ก็ให้สร้างออปเจ็กของคลาสขึ้นมา


  Code

<?php

// prepare database connection variables
$db_host = 'localhost';
$db_name = 'tutor0x';
$db_user = 'user0x';
$db_pass = 'pass0x';

// connect
try {
// If you change db server system, change this too!
$conn = new PDO("mysql:host=$db_host; dbname=$db_name", $db_user, $db_pass);
echo "Connected to database";
}
catch (PDOException $e) {
echo $e->getMessage();
}



ตัวอย่างข้างต้นใช้ MySQL แต่ถ้าต้องการเปลี่ยนเป็นอย่างอื่นก็แก้ไขบรรทัดที่ 12 ให้เป็นระบบฐานข้อมูลนั้น ๆ หากไม่มีการใช้คำสั่ง SQL ที่จำเพาะต่อระบบฐานข้อมูลนั้น ๆ ก็จะไม่ต้องแก้ไขโค้ดในส่วนอื่น ๆ อีก


  Code
<?php

// PostgreSQL
$conn = new PDO("pgsql:host=$db_host port=5432 dbname=$db_name", $db_user, $db_pass);

// Oracle
$conn = new PDO("OCI:dbname=$db_name;charset=UTF-8", $db_user, $db_pass);

// ODBC with MS Access database
$conn = new PDO("odbc:Driver={Microsoft Access Driver (*.mdb)};Dbq="C:database.mdb;Uid=Admin");

// SQLite
$conn = new PDO("sqlite:/path/to/database.sqlite");



ส่วนการปิดการเชื่อมต่อนั้น ตามหลักแล้ว PHP จะปิดการเชื่อมต่อให้โดยอัตโนมัติเมื่อจบสคริปท์ แต่หากต้องการสั่งเองก็ใช้


  Code
<?php
$conn = null;


เมื่อเชื่อมต่อกับฐานข้อมูลได้แล้ว ก็สามารถใช้คำสั่ง SQL จัดการกับฐานข้อมูลได้ 2 วิธี คือ
สั่งโดยตรงผ่านฟังชั่น exec() และ query()
ใช้ฟังชั่น prepare() และ excute()
exec() จะใช้กับคำสั่ง SQL ที่ไม่คืนข้อมูลกลับมา อย่าง INSERT, UPDATE, DELETE เป็นต้น เพราะตัวฟังชั่นจะคืนแต่จำนวนแถวที่ได้รับผลกระทบกลับมา หรือหากทำงานไม่สำเร็จมันจะคืนค่า false กลับมา



  Code
<?php

try {
// connect to database
$conn = new PDO("mysql:host=$db_host; dbname=$db_name", $db_user, $db_pass);
echo "Connected to database n";

// prevent unreadable characters in many languages
$conn->exec("SET CHARACTER SET utf8");

// add data into database
$count = $conn->exec("INSERT INTO application VALUES (null, 'Opera', 'Browser', 'Opera Software ASA', 1994)");

// display result
echo 'Rows add: ' . $count . "n";

// close connection
$conn = null;
}
catch (PDOException $e) {
echo $e->getMessage();
}



หากต้องการข้อมูลกลับมาแสดง หรือประมวลผลให้ใช้ query แทน เวลาจะใช้ก็ใช้ foreach ดึงออกมา


  Code
<?php

// get data
$result = $conn->query("SELECT name,year FROM application");

// display it
if ($result !== false) {
echo 'There is ' . $result->rowCount() . " application(s) in database.n";

foreach($result as $row) {
echo '- ' . $row['name'] . ' was released on ' . $row['year'] . "n";
}
}


แต่ข้อมูลนี้ไม่ใช่อาเรย์ แต่เป็นออปเจ็กของคลาส PDOStatement โดยมีกระบวนการภายในของคลาสคอยจัดการข้อมูลให้ หากไม่ได้กำหนดพารามิเตอร์เพิ่มเติมให้กับฟังชั่น query() ค่าที่ได้จะเป็นทั้ง associative array ที่ใช้ชื่อคอลัมภ์เป็นคีย์ และ numberic array ที่ใช้ตัวเลข (เริ่มจาก 0) เป็น index (ซึ่งภายในมันก็คือตัวเดียวกันนั่นแหละ)

นอกจากใช้ foreach แล้ว สามารถใช้ while() ร่วมกับ fetch() ซึ่งสามารถกำหนดรูปแบบของข้อมูลเพิ่มเติมเข้าไปได้หากต้องการ


  Code
<?php

// get data
$result = $conn->query("SELECT name,year FROM application");

// display it
if ($result !== false) {
echo 'There is ' . $result->rowCount() . " application(s) in database.n";

while($row = $result->fetch()) {
echo '- ' . $row['name'] . ' was released on ' . $row['year'] . "n";
}
}



ฟังชั่น exec() และ query() นั้นมีความเสี่ยงด้านความปลอดภัยอยู่ เราจำเป็นต้องใช้คำสั่ง quote() กับคำสั่ง SQL ด้วยตัวเอง เพื่อป้องกัน SQL Injection หรืออีกวิธีหนึ่งคือ ฟังชั่น prepare() ร่วมกับ execute()

prepare() จะเป็นการเตรียมคำสั่ง SQL ให้พร้อมก่อนที่จะคิวรี่ไปยังฐานข้อมูล


  Code
<?php

// prepare and query (direct)
$result = $conn->prepare("SELECT * FROM application WHERE category='Browser'");
$result->execute();

// display it
if ($result !== false) {
echo $result->rowCount() . " application(s) in Browser category.n";

while($row = $result->fetch()) {
echo '- ' . $row['name'] . ' was released on ' . $row['year'] . "n";
}
}



นอกจากนี้ prepare() ยังรองรับการผูก (bind) ระหว่างอาเรย์เข้ากับคำสั่ง SQL ซึ่งช่วยให้การคิวรี่ข้อมูลมาก ๆ จากฐานข้อมูลทำได้สะดวกขึ้น ซึ่งจะมี 2 แบบ คือ

แบบไม่ตั้งชื่อ จะใช้เครื่องหมาย ? วางไว้ในตำแหน่งที่จะแทรกข้อมูล โดย PHP จะนำข้อมูลไปใส่ให้ตามลำดับ


  Code
<?php

// category that I want to show
$cat = {'OS', 'Office Suite'};

$result = $conn->prepare("SELECT * FROM application WHERE category=? OR category=?");
$result->execute($cat);

if ($result !== false) {
echo 'Found ' . $result->rowCount() . " application(s).n";

while($row = $result->fetch()) {
echo '- ' . $row['name'] . ' was released on ' . $row['year'] . "n";
}
}



อีกแบบคือมีการตั้งชื่อให้กับตำแหน่งที่จะวาง โดยใช้ : นำหน้าชื่อ แล้วใช้ associative array ที่มีคีย์เป็นชื่อเดียวกัน



  Code
<?php

$term = array(
'cat' => 'Browser',
'year' => 2000,
);

// prepare query
$result = $conn->prepare("SELECT * FROM application WHERE category=:cat AND year>:year");

// bind statement and query it
$result->execute($term);

if ($result !== false) {
echo 'Found ' . $result->rowCount() . " application(s).n";

while($row = $result->fetch()) {
echo '- ' . $row['name'] . ' was released on ' . $row['year'] . "n";
}
}



เมื่อจะเปลี่ยนแปลงค่าก็แก้ไขค่าในอาเรย์ แล้วสั่ง execute() ใหม่ได้ทันที


  Code
<?php

function display_data($result) {
if ($result !== false) {
echo 'Found ' . $result->rowCount() . " application(s).n";

while($row = $result->fetch()) {
echo '- ' . $row['name'] . ' was released on ' . $row['year'] . "n";
}
}
}

$term = array(
'cat' => 'Browser',
'year' => 2000,
);

// prepare query
$query = $conn->prepare("SELECT * FROM application WHERE category=:cat AND year>:year");

// bind statement and query it
$query->execute($term);
display_data($query);

// change bind data
$term = array(
'cat' => 'Graphic Editor',
'year' => 1991,
);

// bind with new data and query it
$query->execute($term);
display_data($query);




แม้ว่า PDO จะมีข้อดีเรื่องการทำงานกับระบบฐานข้อมูลได้หลากหลาย แต่หากต้องการรีดประสิทธิภาพ และความเร็วในการจัดการฐานข้อมูลให้มากที่สุด รวมทั้งใช้คำสั่งพิเศษที่มีเฉพาะระบบฐานข้อมูลนั้น ๆ การใช้คำสั่งสำหรับฐานข้อมูลแต่ละตัวเป็นสิ่งจำเป็น ซึ่งก็แลกมาด้วยการแก้ไขโค้ดจำนวนมาก เมื่อต้องการเปลี่ยนฐานข้อมูลเป็นระบบอื่น หรือต้องการให้โปรแกรมที่เขียนขึ้นรองรับฐานข้อมูลที่หลากหลายขึ้น อันนี้ก็ต้องช่างใจกันเอาเอง

แต่หากใช้ framework ต่าง ๆ ในการทำงาน แนะนำให้ใช้คำสั่งเฉพาะที่ framework นั้น ๆ มีให้ แทนที่จะเข้าถึงฐานข้อมูลโดยตรง เพราะ framework จะคอยจัดการเชื่อมต่อ และเตรียมข้อมูลที่คิวรี่ได้มาให้โดยอัตโนมัติ ซึ่งง่าย สะดวก และปลอดภัยกว่า

refer: http://tutor0x.blogspot.com/2012/11/php-pdo.html

ขึ้นไปด้านบน