เขียนเมื่อ 2008-07-23 16:33:10 +0700

ปกติผมจะเขียนโปรแกรมติดต่อฐานข้อมูลโดยฝัง query string เข้าไปในโค๊ดเลย ซึ่งมันก็ง่าย แต่ยากตอนจะเปลี่ยนฐานข้อมูล ก็เลยเขียน class ขึ้นมาเอง แต่ก็ยังติดที่ต้องเขียน method สำหรับแต่ละฐานข้อมูลอยู่ดี ซึ่งฐานข้อมูลบางแบบ ผมไม่ค่อยได้ใช้ (pg sql) หรือไม่เคยใช้เลย (posix, odbc) แต่ก็จำเป็นต้องรู้ไว้บ้างว่าเขียนติดต่อยังไง

หลังจากมาเขียน PHP แบบ OO (แต่ก็ไม่เต็มรูปแบบ) ก็มีคนแนะนำว่า ทำไมไม่ลองใช้ PDO ล่ะ? แรกๆ ก็ไม่ได้สนใจ แต่พอมาจับงานที่ต้องเขียนให้ติดต่อทั้ง PG SQL, MySQL, SQLite แล้วเจอปัญหาเดิมอีก คือ เปลี่ยนฐานข้อมูลลำบาก จะไล่แก้โค๊ดให้หมด ก็บ้าไปแล้ว ก็เลยนึกถึุง PDO ขึ้นมา ลองเล่น ลองลูบ ลองคลำ มันอยู่ 2 อาทิตย์กว่าๆ ก็ได้ Class ส่วนตัวออกมา อิอิ สบายเลย จะเปลี่ยนฐานข้อมูล ก็แก้แค่ไฟล์คอนฟิก

แต่มีข้อแม้ว่า ฐานข้อมูลที่สร้าง ต้องเหมือนกัน และคำสั่ง SQL ทั้งโปรแกรม ต้องไม่มีฟังก์พิเศษที่มีเฉพาะในฐานข้อมูลนั้นๆ เอาง่ายๆ ก็คือ ได้แค่พวก select, insert, delete พื้นๆ น่ะ อยากให้คำนวนอะไรที่แปลกหรือพิสดาร ก็ต้องทำในโปรแกรมแทน อาจจะลำบากตอนเขียน แต่พอเสร็จแล้วก็สบายแหละ

ไฟล์ที่ผมใช้หลักๆ ก็มี 2 ไฟล์ครับ โค๊ดก็ตามนี้เลย (ไม่หวง เอาไปใช้ได้นะ)

config.inc.php ไฟล์นี้สำหรับกำหนดค่าคอนฟิกของเว็ปทั้งหมด บางทีก็เขียนเพิ่มเติมสำหรับบางเว็ปครับ

 <?php
	/**
	*	This file for define constant variable
	*	for PDO Class
	*	Create 2008-07-01 By POP (shikimasan [at] gmail.com)
	*	Support SQLite and MySQL
	*	Can Extends to all DNS
	*/

	define("DB_TYPE", "MySQL"); // MySQL & SQLite
	define("DB_HOST", "localhost");
	define("DB_USERNAME", "mysql username");
	define("DB_PASSWORD", "mysql database");
	define("DB_NAME", "mysql database name");
	define("DB_DNS_MYSQL", "mysql:host=" . DB_HOST . "; dbname=" . DB_NAME);
	define("DB_DNS_SQLITE", "sqlite:db/sqlite_file");
	define("DB_PREFIX", "yourdatabase_");
?> 

connection.inc.php ไฟล์นี้เป็นตัวติดต่อฐานข้อมูลชนิดต่างๆ

 <?php
	/**
	*	This file define Class to Connect and Query PDO Statement
	*	Don't forget to include config.inc.php
	*	Create 2008-07-01 By POP (shikimasan [at] gmail.com)
	*/

	require_once('config.inc.php');

	class Connect extends PDO {
		public function __construct() {
			try {
				if (DB_TYPE == "MySQL") {
					parent::__construct(DB_DNS_MYSQL, DB_USERNAME, DB_PASSWORD, array(PDO::MYSQL_ATTR_INIT_COMMAND => "set names utf8"));
				}
				elseif (DB_TYPE == "SQLite"){
					parent::__construct(DB_DNS_SQLITE);
				}
				$this -> setAttribute(PDO::ATTR_STATEMENT_CLASS, array('DatabaseStatement', array($this)));
			}
			catch (PDOException $e) {
				$e -> getMessage();
			}
		}
		public function __destruct() {
		}
	}

	class DatabaseStatement extends PDOStatement {
		public $dbc;
		private function __construct($dbc) {
			$this -> dbc = $dbc;
			$this -> setFetchMode(PDO::FETCH_ASSOC);
		}
		public function __destruct() {
			$this -> dbc = NULL;
		}
	}
?> 

เวลาเอาไปใช้งานจริง ก็แค่สร้างเป็น Object โดยใช้คำสั่ง new เท่านั้นเอง หรือจะเขียนเพิ่มแล้วสืบทอดคลาสนี้ไปก็ได้ ยกตัวอย่าง ผมสร้างคลาสที่รวม method ที่ผมใช้งานบ่อยๆ ในนั้นมี method ที่ทำการเพิ่มวันที่ ผมก็เขียนคลาสใหม่ แบบนี้

 <?php
	require_once('connection.inc.php');

	class PopClasses extends Connect {
		public function getAddDate($basedate, $day) {
			return date("Y-m-d", strtotime($basedate . "+" . $day . " day"));
		}
	}

	// เวลาเอาไปใช้งานจริงๆ
	require_once('../include/PopClasses.inc.php');
	$conn = new PopClasses();
	$conn -> beginTransaction();
	$_POST['passwd'] = md5($_POST['passwd']);	// SQLite ไม่มีฟังก์ชั่น md5 เลยต้องทำบน php แทน
	$SQLCom = "insert into " . DB_PREFIX . "account(username, passwd, name, lv) values('" . $_POST['username'] . "', '" . $_POST['passwd'] . "', '" . $_POST['name'] . "', '" . $_POST['lv'] . "')";
	$conn -> exec($SQLCom) or die($conn -> viewVar($conn -> errorInfo()));
	$conn -> commit();
?> 

ง่ายๆ เลยใช่ไหมครับ ถ้าต้องการเปลี่ยนฐานข้อมูลก็ไปแก้แค่ที่เดียวเอง

ที่เหลือ ลองเอาต่อยอดกันได้เลยครับ ไม่หวงอยู่แล้ว หรือถ้าติดขัดอะไรก็ฝากข้อความไว้ได้เหมือนกันครับ

ปล. มาดูทีหลัง ผมใช้ tap แทนการกด space ออกมาไม่สวยเลย งานหน้า จะทำให้เนียนกว่านี้ครับ

Comments

จำนวนความเห็น