เราพบว่า PHP ช่วยในการสร้างเว็บไซต์แบบ dynamic เพราะเป็นภาษาที่มีความยุ่งยากน้อยที่สุด และสนุกที่สุด การสร้างเว็บไซต์เหล่านี้ เราจำเป็นต้องใช้ฐานข้อมูลในการถึงข้อมูลเพื่อการ login, ในการดึงข้อมูลข่าวสารเพื่อแสดงบนเว็บเพจ และในการจัดเก็บข้อมูลที่เรา post ในกระทู้ ดังนั้นเราจึงใช้ MySQL ซึ่งเป็นระบบฐานข้อมูลที่อยู่ในความนิยมสำหรับทำงานเหล่านี้ แต่เมื่อเราพบว่า เว็บไซต์ของเราเป็นที่นิยมมากกว่าที่เราคิดไว้ เราก็จะพบว่า MySQL ไม่สามารถจัดการงานข้อมูลเยอะๆ ของเราได้ มันก็ถึงเวลาสมควรที่จะเปลี่ยนไปใช้ระบบฐานข้อมูลอื่นแล้ว
แต่ PHP ใช้การเข้าถึงระบบฐานข้อมูล ด้วยวิธีที่แตกต่างกัน ถ้าจะเข้าถึง MySQL เราจะใช้ mysql_connect() และเมื่อเราตัดสินใจที่จะ upgrade เป็น Oracle หรือ MS SQL Server เราจะใช้ ocilogon() หรือ mssql_connect() แทน และสิ่งที่เลวร้ายไปกว่านั้นก็คือ parameter ที่เราใช้สำหรับการเข้าถึงนั้นก็แตกต่างกันด้วยเช่นกัน ก็จะเหมือน ระบบฐานข้อมูลหนึ่งพูด po-tato อีกระบบฐานข้อมูลพูด pota-to
Let’s call the whole thing off เลิกการเรียกใช้ทุกอย่าง
เมื่อเป็นเช่นนี้ การใช้ database wrapper library เช่น ADODB จึงเป็นประโยชน์อย่างมาก เมื่อเราต้องการความมั่นใจในการใช้งานแบบ portability ซึ่งการใช้ wrapper library นี้ เราจะมี common API ที่รองรับการติดต่อกับระบบฐานข้อมูลใดๆ ก็ได้ ทำให้เราไม่จำเป็นต้องเปลี่ยนคำสั่งในการติดต่อฐานข้อมูลแต่ละชนิดทุกครั้งที่เราเปลี่ยนระบบฐานข้อมูล
ADODB ย่อมาจาก Active Data Objects DataBase ซึ่งปัจจุบันรองรับการทำงานกับ MySQL, PostgreSQL, Oracle, Interbase, Microsoft SQL Server, Access, FoxPro, Sybase, ODBC และ ADO
ตัวอย่าง MySQL
แน่นอนว่า ระบบฐานข้อมูลที่ใช้กันมากที่สุดกับ PHP คือ MySQL ดังนั้น เราคงคุ้นเคยกับ code ต่อไปนี้ มันจะติดต่อกับ MySQL Server ที่ localhost, ฐานข้อมูล คือ mydb และใช้คำสั่ง SQL select ซึ่งผลลัพธ์จะพิมพ์ออกมาทีละบรรทัด
// ทำการติดต่อไปยังฐานข้อมูล
$db = mysql_connect(”localhost”, “root”, “password”);
mysql_select_db(”mydb”,$db);
// ใช้คำสั่ง SQL
$result = mysql_query(”SELECT * FROM employees”,$db);
if ($result === false) die(”failed”);
// วนลูปแถวข้อมูลที่ได้มา
while ($fields = mysql_fetch_row($result)) {
// วนลูป field ในแถวข้อมูล
for ($i=0, $max=sizeof($fields); $i < $max; $i++) {
print $fields[$i].’ ‘;
}
print ”
n”;
}
ถ้าเราใช้ ADODB เราจะได้ code เป็นดังนี้
include(”adodb.inc.php”);
$db = NewADOConnection(’mysql’);
$db->Connect(”localhost”, “root”, “password”, “mydb”);
$result = $db->Execute(”SELECT * FROM employees”);
if ($result === false) die(”failed”);
while (!$result->EOF) {
for ($i=0, $max=$result->FieldCount(); $i < $max; $i++)
print $result->fields[$i].’ ‘;
$result->MoveNext();
print ”
n”;
}
ดังนั้น ถ้าเราจะเปลี่ยนระบบฐานข้อมูลเป็น Oracle ก็สามารถทำได้ง่าย เพียงแค่เปลี่ยน code ในบรรทัดที่ 2 ให้เป็น
$db = NewADOConnection(’oracle’);
เรามาดูรายละเอียดของ code กัน
การติดต่อกับระบบฐานข้อมูล
include(”adodb.inc.php”);
$db = NewADOConnection(’mysql’);
$db->Connect(”localhost”, “root”, “password”, “mydb”);
การเขียน code เพื่อติดต่อกับระบบฐานข้อมูล มีความยุ่งยากกว่าของ MySQL เพราะความจำเป็นในการติดต่อของเรามันยุ่งยากกว่า ใน ADODB เราใช้วิธี object-oriented ในการจัดการความซับซ้อนของการจัดการระบบฐานข้อมูลหลายๆ ระบบ เรามี class ต่างๆ ที่ใช้ในการจัดการระบบฐานข้อมูลที่แตกต่างกัน แต่ไม่ต้องกังวล ถ้าเราไม่คุ้นเคยกับการเขียน object-oriented ความซับซ้อนต่างๆ ถูกซ่อนไว้ภายใน function NewADOConnection() แล้ว
เพียงแค่จำไว้ว่า เราเพียงแค่ใช้ PHP code ในการระบุระบบฐานข้อมูลที่เราจะติดต่อด้วยเท่านั้น โดยการเรียก NewADOConnection(databasedriver) ซึ่ง database driver ที่ใช้คือ mysql, mssql, oracle, oci8, postgres, sybase, vfp, access, ibase และอื่นๆ อีกมากมาย
หลังจากนั้น ในตัวอย่าง เราจึงสร้าง class สำหรับการติดต่อระบบฐานข้อมูลใหม่ โดยใช้ NewADOConnection() และสุดท้ายทำการติดต่อระบบฐานข้อมูลโดยใช้ $db->Connect()
การใช้คำสั่ง SQL
$result = $db->Execute(”SELECT * FROM employees”);
if ($result === false) die(”failed”);
การส่งคำสั่ง SQL ให้กับ server ทำแบบโดยตรง ซึ่ง method Execute() จะคืนค่า recordset object ที่ได้จากการสั่ง execute สำเร็จกลับมา ซึ่งเราควรตรวจสอบ $result ด้วยว่าสำเร็จ หรือล้มเหลว
ผู้ที่เริ่มต้นใช้งาน อาจจะสับสนว่า มี object 2 ชนิดที่ใช้ใน ADODB นั่นคือ connection object และ recordset object แล้วเราจะใช้ object เหล่านี้เมื่อไร
สำหรับ connection object หรือ $db จะใช้ในการติดต่อกับระบบฐานข้อมูล, จัดรูปแบบคำสั่ง SQL และดึงข้อมูลจากระบบฐานข้อมูล ส่วน recordset object จะใช้ในการดึงผลลัพธ์ และจัดรูปแบบข้อมูลที่ได้เป็น text หรือเป็น array
ADODB ได้มี function มากมายที่ช่วยในการใช้คำสั่ง INSERT และ UPDATE ง่ายขึ้น ซึ่งเราจะอธิบายในส่วนต่อไป
การดึงข้อมูล
while (!$result->EOF) {
for ($i=0, $max=$result->FieldCount(); $i < $max; $i++)
print $result->fields[$i].’ ‘;
$result->MoveNext();
print ”
n”;
}
แบบอย่างของการดึงข้อมูล เหมือนกับการอ่านไฟล์ ในแต่ละบรรทัด เราจะตรวจสอบก่อนว่า เราอ่านมาถึงบรรทัดสุดท้าย (EOF) หรือยัง ถ้ายังไม่ถึงบรรทัดสุดท้าย จะวนลูปไปทีละ field ในแถวข้อมูลนั้น แล้วก็วนไปอ่านบรรทัดต่อไป (MoveNext) และก็ทำซ้ำไปเรื่อยๆ
$result->fields[] เป็น array ที่ถูกสร้างขึ้นโดย PHP database extension ซึ่งบาง database extension ไม่มีการจัดลำดับของ array โดยใช้ชื่อ field ถ้าเราต้องการบังคับให้เรียงลำดับโดยใช้ชื่อ หรือทำ associative array เราจะใช้ตัวแปร global คือ $ADODB_FETCH_MODE
$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
$rs1 = $db->Execute(’select * from table’);
$ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
$rs2 = $db->Execute(’select * from table’);
print_r($rs1->fields); // shows array([0]=>’v0′,[1] =>’v1′)
print_r($rs2->fields); // shows array([’col1′]=>’v0′,[’col2′] =>’v1′)
จากตัวอย่างข้างบน recordset ทั้งสองอัน จะจัดเก็บ และใช้ fetch mode ที่ต่างกัน แต่อยู่บนพื้นฐานของการกำหนด $ADODB_FETCH_MODE เมื่อ recordset ถูกสร้างโดยใช้ method Execute()
ADOConnect
เป็น Object ที่ใช้ในการติดต่อฐานข้อมูล, สั่งให้ทำงานตามคำสั่ง SQL และกำหนด utility function สำหรับมาตรฐานในการจัดรูปแบบของคำสั่ง SQL เช่นการนำมารวมกัน หรือจัดรูปแบบวันที่
Function อื่นๆ
$recordset->Move($pos) ใช้ในการวิ่งไปยังแถวข้อมูลที่ระบุ ADODB จะรองรับการวิ่งไปบรรทัดข้างหน้าในทุกระบบฐานข้อมูล บางระบบฐานข้อมูลจะไม่รองรับการวิ่งย้อนกลับไปบรรทัดก่อนหน้า ซึ่งก็ไม่ใช่ปัญหาใหญ่อะไร เพราะเราสามารถเก็บข้อมูลเหล่านี้ไว้ เพื่อการวิ่งย้อนกลับได้อยู่แล้ว
$recordset->RecordCount() จะ return จำนวนแถวข้อมูลที่ได้จากการสั่งคำสั่ง SQL บางระบบฐานข้อมูลที่ไม่รองรับการทำงานนี้ จะส่งค่า -1 กลับมา
$recordset->GetArray() จะ return ผลลัพธ์กลับมาเป็น array
rs2html($recordset) เป็น function ที่สร้างตาราง HTML โดยใช้ข้อมูลจาก $recordset ในการสร้าง ตัวอย่างการใช้งาน แสดงเป็นตัวหนาใน code นี้
include(’adodb.inc.php’);
include(’tohtml.inc.php’); /* includes the rs2html function */
$conn = &ADONewConnection(’mysql’);
$conn->PConnect(’localhost’,'userid’,'password’,'database’);
$rs = $conn->Execute(’select * from table’);
rs2html($rs); /* recordset to html table */
Advanced Material
การใช้ Inserts และ Updates
จากตัวอย่างนี้ เราต้องการเพิ่มข้อมูลต่อไปนี้เข้าไปในระบบฐานข้อมูล
ID = 3
TheDate = mktime(0,0,0,8,31,2001) /* 31st August 2001 */
Note = sugar why don’t we call it off
ถ้าเราย้ายไประบบฐานข้อมูลอื่นๆ เราก็ไม่ต้องแก้ไข code มากนัก
จากตัวอย่างนี้ เราจะพบปัญหาแรกคือ ระบบฐานข้อมูลแต่ละอันใช้รูปแบบวันที่ที่แตกต่างกัน เช่น MySQL จะใช้รูปแบบ YYYY-MM-DD แต่ระบบฐานข้อมูลอื่น จะใช้รูปแบบวันที่อื่น ด้วยเหตุนี้ ADODB จึงมี function ชื่อว่า DBDate() เพื่อแก้ปัญหานี้ โดย function นี้จะแปลงรูปแบบวันที่ให้ถูกต้อง
ปัญหาถัดไป คือ การใช้ ‘ ในคำว่า ” don’t ” ใน MySQL เราสามารถใส่คำว่า ” don’t ” ได้เลย แต่บางระบบฐานข้อมูล เช่น Sybase, Access หรือ MS SQL Server เราต้องใส่คำว่า ” don”t ” แทน ดังนั้น ADODB จึงมี function ชื่อว่า qstr() ให้ใช้ เพื่อแก้ปัญหานี้
เมื่อเป็นเช่นนี้ เราจึงใช้ 2 function นี้ในการนำเข้าข้อมูล
$sql = “INSERT INTO table (id, thedate,note) values (”
. $ID . ‘,’
. $db->DBDate($TheDate) .’,’
. $db->qstr($Note).”)”;
$db->Execute($sql);
นอกจากนี้ ADODB ยังสนับสนุนการคืนจำนวนแถวข้อมูลที่ถูกแก้ไข หรือลบครั้งล่าสุดด้วย โดยใช้ $connection->Affected_Rows() ส่วน $recordset->Insert_ID() จะคืนค่าหมายเลขล่าสุดที่ถูกสร้างขึ้นอัตโนมัติจากการใช้คำสั่ง insert แต่อย่างไรก็ตาม ยังมีบางระบบฐานข้อมูลที่ไม่สนับสนุนการใช้งานของ 2 function นี้
การใช้ MetaTypes
เราสามารถค้นหาข้อมูลเกี่ยวกับ field หรือ column ต่างๆ ได้โดยการใช้ method FetchField($fieldoffset) ซึ่งจะคืนค่า object ที่มี 3 คุณลักษณะ คือ name, type และ max_length
ตัวอย่างเช่น
$recordset = $conn->Execute(”select adate from table”);
$f0 = $recordset->FetchField(0);
ทำให้
$f0->name มีข้อมูลของ ‘adate’
$f0->type ถูกกำหนดให้เป็น ‘date’
และ max_length จะไม่มีค่า ซึ่งถูกกำหนดให้เป็น -1
อีกปัญหาหนึ่งที่พบในการจัดการระบบฐานข้อมูลที่แตกต่างกัน คือ แต่ละระบบฐานข้อมูลมักจะเรียกชนิดข้อมูลแบบเดียวกันด้วยชื่อที่แตกต่างกัน ตัวอย่างเช่น ชนิดข้อมูลแบบ timestamp จะถูกเรียกเป็น datetime ในระบบฐานข้อมูลหนึ่ง และถูกเรียกเป็น time ในอีกระบบฐานข้อมูล ดังนั้น ADODB จึงมี function พิเศษชื่อว่า MetaType($type, $max_length) ซึ่งช่วยในการจัดมาตรฐานการเรียกชื่อชนิดข้อมูลต่างๆ ดังนี้
C: character and varchar types
X: text or long character (eg. more than 255 bytes wide).
B: blob or binary image
D: date
T: timestamp
L: logical (boolean)
I: integer
N: numeric (float, double, money)
ดังนั้น จากตัวอย่างวันที่ข้างบน เราจะได้ code ดังนี้
$recordset = $conn->Execute(”select adate from table”);
$f0 = $recordset->FetchField(0);
$type = $recordset->MetaType($f0->type, $f0->max_length);
print $type; /* should print ‘D’ */
สนับสนุนการใช้ Select Limit และ Top
ADODB มี function ที่เรียกว่า $connection->SelectLimit($sql, $nrows, $offset) ที่อนุญาตให้เราดึง subset ของ recordset มาใช้งานได้ ซึ่งจะเป็นประโยชน์ต่อการใช้ SELECT TOP ของผลิตภัณฑ์ Microsoft และ SELECT…LIMIT ใน PostgreSQL และ MySQL ซึ่งสามารถนำมาใช้ได้ ถ้าระบบฐานข้อมูลอื่นไม่สนับสนุนการใช้งานนี้
สนับสนุนการทำ Caching
ADODB อนุญาตให้เรา cache ตัว recordset ไว้ใน file system ของเราได้ และจะทำการ requery จากฐานข้อมูลเมื่อถึงเวลาที่กำหนดไว้เท่านั้น โดยใช้คำสั่ง $connection->CacheExecute($secs2cache, $sql) และ $connection->CacheSelectLimit($secs2cache, $sql, $nrows, $offset)
สนับสนุนการจัดการ session ของ PHP4
ADODB ได้สนับสนุนการจัดการ session ของ PHP4 ด้วย ซึ่งเราสามารถจัดเก็บตัวแปร session ในฐานข้อมูล เพื่อการใช้ ADODB ที่มีประสิทธิภาพ
การใช้งานแบบเชิงพาณิชย์
ถ้าเราวางแผนที่จะพัฒนาโปรแกรม PHP ในเชิงพาณิชย์ ที่ต้องการขายได้อีกเรื่อยๆ เราควรจะพิจารณาการใช้ ADODB ซึ่งได้ถูก release โดยใช้ GPL ที่น้อยกว่า ซึ่งหมายความว่า เราสามารถรวมเข้ากับโปรแกรมเชิงพาณิชย์ได้อย่างถูกต้องตามกฏหมาย ในขณะที่เราสามารถเก็บเป็น code ของเราเอง เราจึงแนะนำและสนับสนุนให้ใช้ ADODB ในเชิงพาณิชย์ และเราก็กำลังใช้มันด้วยเช่นกัน
เปรียบเทียบ PHP function ของ Mysql กับ ADOdb
Function |
Mysql_xxx |
ADOdb |
การ connect | mysql_connect(”localhost”, “root”, “password”); | include(”adodb.inc.php”); $db = NewADOConnection(’mysql’); $db->Connect(”localhost”, “root”, “password”, “mydb”); |
การ รันคำสั่ง SQL | mysql_query($sql) | $db->Execute($sql) |
การวน loop เพื่อแสดงผลข้อมูลทั้งหมด | while ($fields = mysql_fetch_row($result)) { // วนลูป field ในแถวข้อมูล for ($i=0, $max=sizeof($fields); $i < $max; $i++) {
print $fields[$i].’ ‘; } print ” n”; } |
while (!$result->EOF) { for ($i=0, $max=$result->FieldCount(); $i < $max; $i++) print $result->fields[$i].’ ‘;
$result->MoveNext(); print ” n”; } |
การตรวจจับ error ของคำสั่ง sql | $result = mysql_query($sql); if ($result === false) die(”failed”); | $result = $db->Execute($sql); if ($result === false) die(”failed”); |
การยัดค่าใส่ตัวแปล array | while ( $rs = mysql_fetch_row($result) ) { # process $arr } | $rs = $db->Execute($sql); if ($rs) while ($arr = $rs->FetchRow()) {
# process $arr } |
การรับค่าทั้งหมด ของ ผลการ รัน คำสั่ง sql ใส่ตัวแปล | - | $db->GetArray(), $db->GetRow($sql) $db->GetAll($sql) |
สร้าง list manu จะผลของ การรันคำสั่ง sql | - | $rs = $conn->Execute($sql); print $rs->GetMenu(‘ชื่อlistmanu’,‘ค่าที่ถูกselect’,true); data ต้อง เป็น ( name,id ) |
การแสดงผล ข้อมูล ที่ละหน้า | ต้องเขียน โค้ดแบ่งหน้า เอง | include_once(’adodb.inc.php’); include_once(’adodb-pager.inc.php’); session_start();
$db = NewADOConnection(’mysql’); $db->Connect(’localhost’,'root’,”,’xphplens’); $sql = “select * from adoxyz “; $pager = new ADODB_Pager($db,$sql); $pager->Render($rows_per_page=5); |
นับจำนวน recode ทั้งหมด | mysql_num_rows($result) | $db->RecordCount($result) |
แสดงผล error ด้วย pear | ต้องเขียน ดึง pear มาให้เอง | include(‘adodb-errorpear.inc.php’); if error แสดง ค่าด้านล้างๆด้เลย $e = ADODB_Pear_Error();
echo ‘ ‘,$e->message,‘ ‘; |
การ รัน sql เพื่อ จำกัด ประริมาณข้อมูล | ต้องเขียนที่ คำสั่ง sql | $db->SelectLimit($sql,$numrows=-1,$offset=-1,$inputarr=false) |
March 9th, 2008 at 4:26 pm
สุดยอด เจ๋งจิงๆ
แต่สงสัยว่า จะใช้กับ OS อะไรได้บ้างอะ ในกรณีที่ OS เป็น unix จะใช้ได้ไหม? อะ หรือวิธีนี้ไม่เกี่ยวกับ OS อะ ตอน config server ต้องทำอะไรเพิ่มไหม? อะ
March 10th, 2008 at 9:32 am
ตอบแบบความเห็นส่วนตัวจากปัญญาอันน้อยนิดนะคับ อาจจะไม่ถูกนะคับ
เพราะผมเองก็ยังไม่ไดลองใช้เพียงแต่อ่านเจอแล้วรู้สึกว่าเป็นแนวทางที่ดีในการพัฒนาโปรแกรมนะคับ
คาดว่าไม่น่าจะเกี่ยวกับ OS อะพี่เกี๋ยวกับ version php มากกว่าอะพี่ เพราะมันอาจจะต้องสนับสนุนการเขียนแบบ OOP ก็ต้องใช้ php5 มั้งคับ
ถ้าใครเคยเข้า class ajax ของ อ.นพดล อาจคุ้นเคยกับ class ajax ของ อาจารย์เค้านะคับ หรืออาจจะเป็นพวก pdfthai ที่ใช้ class อะคับ
^-^ มั่วคับ