Tag Archives: phpbb

ทำความรู้จักกับ SQL Layer ของ phpBB

5 Jun

เชื่อว่าบางคนที่เคยทดลองเขียน Web Appication กับฐานข้อมูลมากกว่า 1 ยี่ห้อ น่าจะเคยประสบปัญหานี้กันมาบ้างพอสมควร
ตัวอย่างเช่น สมมติว่าเราจะเขียน PHP เพื่อเรียกดูข้อมูลจาก MySQL เราจะทำตามขั้นตอนต่อไปนี้

  1. เชื่อมต่อกับฐานข้อมูลด้วย mysql_connect หรือ mysql_pconnect
  2. เลือกฐานข้อมูลด้วย mysql_select_db
  3. ส่ง query ไปประมวลผลด้วย mysql_query
  4. เรียกดูข้อมูลทีละ row ด้วย mysql_fetch_array, mysql_fetch_assoc หรือ mysql_fetch_row หรืออะไรก็ตาม แล้ววนลูป

ถ้าเปลี่ยนมาเขียน PHP (ผู้เขียนเขียน .NET กับ jsp ไม่เป็นครับ เห็นใจหน่อยละกัน) เพื่อเรียกข้อมูลจาก Oracle จะมีขั้นตอนต่อไปนี้

  1. เชื่อมต่อกับฐานข้อมูลด้วย oci_connect
  2. เตรียมประมวลผล query ด้วย oci_parse
  3. ประมวลผลด้วย oci_execute
  4. เรียกดูข้อมูลด้วย oci_fetch_array

จะเห็นว่ามี 4 ขั้นตอนเหมือนกันก็จริง แต่แต่ละขั้นตอนกลับต่างกัน เช่น
กรณีของ MySQL: ไม่ต้องมา parse แล้วตามด้วย execute เพราะ mysql_query อย่างเดียวก็เหมือนได้ทำสองขั้นตอนนั้นครบแล้ว
กรณีของ Oracle: ไม่ต้องมีการเลือกฐานข้อมูล (mysql_select_db)

เมื่อเป็นเช่นนี้แล้ว ปัญหาย่อมตามมาแน่่ถ้าเกิดมีคนคิดพิเรนทร์ อยากจะเปลี่ยนจากฐานข้อมูลยี่ห้อหนึ่งไปใช้อีกยี่ห้อหนึ่ง
และอีกปัจจัยหนึ่งคือ CMS บางยี่ห้อ เช่น phpBB มีข้อได้เปรียบคือ สามารถใช้งานกับฐานข้อมูลได้หลายๆ ยี่ห้อ
ดังนั้นคงจะไม่ดีแน่ที่จะให้มาเขียนโปรแกรมเดียวกันออกเป็นหลาย copy เพื่อให้สามารถใช้งานกับโปรแกรมฐานข้อมูลหลายๆ ตัว

แนวคิดเกี่ยวกับ sql layer ก็มีแนวคิดคล้ายๆ กับเรื่อง virtual machine แหละครับ
คือ sql layer จะเป็น layer ที่ซ่อนความแตกต่างระหว่างฐานข้อมูลแต่ละยี่ห้อเอาไว้ เหมือนกับที่โปรแกรมภาษาจาวาสามารถรันได้บน JVM โดยที่ไม่ต้องคำนึงว่าอยู่บน OS อะไร

SQL Layer ของ phpBB เป็นโอเพนซอร์สครับ สามารถดาวน์โหลดมาศึกษาดูได้จากการดาวน์โหลด phpBB (SQL Layer ของphpBB3 ถูกเขียนขึ้นมาใหม่ ซึ่งแตกต่างจาก phpBB2 ในที่นี้ขอใช้ phpBB2)
ไฟล์ที่เกี่ยวข้องกับ SQL Layer จะอยู่ใน /phpBB2/db ครับ
เมื่อ ลองเปิดดูแต่ละไฟล์ (เช่น db2.php, msaccess.php, mssql.php, mysql.php, oracle.php, ฯลฯ) จะพบว่าชื่อฟังก์ชันแต่ละฟังก์ชันภายในคลาส sql_db ของแต่ละไฟล์ จะตรงกันหมด ต่างกันที่การทำงานภายในฟังก์ชันเท่านั้น

ขอแนะนำฟังก์ชันที่ใช้กันบ่อยๆ แล้วกันครับ

  1. sql_db เป็น constructor การเปิดการเชื่อมต่อกับฐานข้อมูลรวมทั้งการเลือกกระทำกับฐานข้อมูลใดฐาน ข้อมูลหนึ่ง จะเกิดขึ้นจากการเรียกฟังก์ชันนี้
  2. นอกจากนี้ ในกรณีที่เราต้องการ manipulate ข้อมูลที่เป็นภาษาไทย ก็สามารถเข้ามาแก้ไขโค้ดได้ที่ฟังก์ชันนี้ครับ (ว่าแต่ แก้จากข้างนอกดีกว่ามั้ง)
  3. sql_query สำหรับผู้ที่คุ้นเคยกับ mysql ฟังก์ชันนี้ทำหน้าที่เหมือนกับฟังก์ชัน mysql_query ครับ
  4. sql_fetchrow เป็นฟังก์ชันที่ดึงข้อมูลที่ได้จากฟังก์ชัน sql_query มาแสดงทีละแถว
  5. sql_numfields คืนค่าจำนวนฟิลด์ของตาราง
  6. sql_numrows คืนค่าจำนวนแถว

ขอแสดงตัวอย่างการใช้งานโดยเปรียบเทียบกับสคริปต์ที่เขียนปกติโดยไม่ใช้เครื่องมือตัวนี้ (กับฐานข้อมูล MySQL)

//กรณีที่ไม่ใช้ sql_db
<?php
$link = mysql_connect(‘mysql_host’, ‘mysql_user’, ‘mysql_password’)
or die(‘Could not connect: ‘ . mysql_error());
mysql_select_db(‘my_database’) or die(‘Could not select database’);
$query = ‘SELECT * FROM my_table’;
$result = mysql_query($query) or die(‘Query failed: ‘ . mysql_error());
while ($line = mysql_fetch_array($result)) {

}
mysql_free_result($result);
mysql_close($link);
?>

//กรณีที่ใช้ sql_db
<?php
include(“./db/mysql.php”);
$db = new sql_db(‘mysql_host’, ‘mysql_user’, ‘mysql_password’, ‘my_database’, false);
$query = ‘SELECT * FROM my_table’;
$result = $db->sql_query($query);
while ($line = $db->sql_fetchrow($result)) {

}
$db->sql_close();
?>

สังเกต ว่า โค้ดสั้นลง ทั้งนี้เพราะภายในฟังก์ชันของ sql_db มีการจัดการเกี่ยวกับ error ภายในฟังก์ชันอยู่แล้ว เราไม่จำเป็นต้องมา or die(‘error message’) เอาเอง

สุดท้ายนี้ สิ่งที่อยากจะบอกคือ ฟังก์ชัน sql_rowseek ใน oracle.php มันทำงานผิดครับ
ถ้าอยากให้มันทำงานได้ถูกต้อง ลองเข้าไปแก้ไขดูแล้วกัน แก้ไม่เกิน 2 บรรทัด รับรอง ^ ^