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
ขึ้นไปด้านบน
