การใช้ MySQLi แทนการใช้ฟังก์ชั่น mysql_xxxxx() นั้น เขียนได้ 2 แบบคือ
แบบ OOP (เรียกใช้ method ของ object)
กับแบบ Procedural (เรียกใช้ฟังก์ชั่น)
ในบทความนี้จะกล่าวถึงแบบ OOP เท่านั้น เพราะการเขียนแบบ OOP นั้นมีโอกาสที่จะเกิดความผิดพลาดน้อยกว่า
เหตุผลคือ การเขียน MySQLi แบบ Procedural จะต้องมีการส่งตัวแปร mysqli object ทุกครั้ง
พูดง่ายๆ คือต้องเขียนยาวกว่า และอาจจะสับสนได้ง่ายกว่า
และอาจจะทำงานช้ากว่า เพราะแบบหลังอาจจะเป็นแค่การเรียก method ของ object ที่ส่งไปในแบบ OOP นั่นเอง
การเชื่อมต่อฐานข้อมูลด้วย MySQLi
ก่อนจะใช้ MySQLi นั้น ก็เหมือนกับการใช้ฟังก์ชั่น mysql_xxxxx()
คือต้องเชื่อมต่อกับ MySQL Server ก่อน ซึ่งในแบบเดิมเราใช้ mysql_connect()
แต่ในการเขียนด้วย MySQLi จะทำได้สองแบบ
1. ด้วย MySQLi::__construct() หรือการ new mysqli()
แบบนี้จะสามารถสร้าง MySQLi Object และทำการเชื่อมต่อไปได้ในคำสั่งเดียว
2. สร้าง MySQLi Object ด้วย mysqli_init() และเชื่อมต่อด้วย MySQLi::real_connect()
โดย mysqli_init() จะสร้าง MySQLi Object ให้เพื่อเอาไปใช้กับ MySQLi::options() และ MySQLi::real_connect()
ความแตกต่างกับแบบแรกคือ แบบแรกจะไม่สามารถกำหนด options ให้กับการเชื่อมต่อ
เช่น ระยะเวลา timeout, คำสั่ง SQL เริ่มต้น, ตั้งค่าการเชื่อมต่อแบบ SSL ฯลฯ
ดังนั้นในส่วนของการเชื่อมต่อ เราใช้ method/function ดังนี้
MySQLi::__construct()
mysqli_connect()
สร้าง MySQLi Object และเชื่อมต่อฐานข้อมูลไปในคราวเดียว
mysqli_init()
สร้าง MySQLi Object เพื่อใช้ในการตั้งค่าด้วย MySQLi::options() และเชื่อมต่อด้วย MySQLi::real_connect()
MySQLi::real_connect()
เชื่อมต่อฐานข้อมูล โดยต้องเป็น MySQLi Object ที่สร้างขึ้นจาก mysqli_init() เท่านั้น
MySQLi::$connect_errno
MySQLi::$connect_error
เป็น property ที่บอกว่า การเรียกใช้ MySQLi::__construct() หรือ MySQLi::real_connect() นั้นมีความผิดพลาดเกิดขึ้นหรือไม่
โดย MySQLi::$connect_errno เป็นตัวเลขของ error code
ส่วน MySQLi::$connect_error จะเป็น error message
หากไม่มี error เกิดขึ้น MySQLi::$connect_errno จะมีค่าเป็น 0
ส่วน MySQLi::$connect_error จะมีค่าเป็น ''
การใช้คำสั่ง SQL
เมื่อเราได้ MySQLi Object จากการเชื่อมต่อฐานข้อมูลที่สำเร็จแล้ว
ก็มาถึงการใช้งาน MySQLi Object นั้นๆ ซึ่งโดยปกติก็คือการส่งคำสั่ง SQL ไปให้ MySQL Server ประมวลผล
ในการเขียนแบบเก่าเราใช้ฟังก์ชั่น mysql_query()
แต่ในแบบใหม่ เราจะใช้ method MySQLi::query() หรือ MySQLi::real_query() และอื่นๆ
MySQLi::query()
ส่งคำสั่ง SQL ไปให้ MySQL Server ประมวลผล
MySQLi_Result Object
เป็น Object ที่จะได้จากการเรียกใช้ method MySQLi::query() (และอื่นที่คล้ายคลึงกัน)
ซึ่งเป็น Object ที่มี method ในการตรวจสอบและดึงข้อมูล
กระบวนการ query และรับ result นี้ ผมขอเปรียบกับการสั่งซื้อของกับยี่ปั๊วทางโทรศัพท์
ซึ่งการ query คือการโทรไปสั่งซื้อ บอกว่าต้องการอะไร
และ result ที่ได้รับกลับคืนมาจากการ query นั้น "ยังไม่ใช่สินค้า"
แต่เป็น "รถขนสินค้าและพนักงานยกของ"
MySQLi_Result::fetch_xxxxx()
เป็น method ที่ใช้ดึงข้อมูลที่ได้มาจากการ query ซึ่งมีหลาย method ด้วยกัน แตกต่างตามชนิดข้อมูลที่คืนมา
โดยปกติเราจะใช้ MySQLi_Result::fetch_assoc() เป็นหลัก
และไม่ควรใช้ MySQLi_Result::fetch_array() เพราะจะทำให้เปลืองหน่วยความจำโดยใช่เหตุ
MySQLi_Result::free()
ทำลายข้อมูลที่ query มาก่อนหน้า เพื่อคืนหน่วยความจำให้กับระบบ
ในการ query เพื่อให้ได้ MySQLi_Result Object นั้น ทุกๆ ครั้ง MySQL จะต้องเก็บผลลัพธ์ที่ได้ไว้ใน buffer ก่อน
ซึ่งอาจจะเป็นในหน่วยความจำ (RAM) หรือในฮาร์ดดิสก์
หลังจากนั้นจึงให้ผู้ใช้อ่านข้อมูลด้วย method fetch_xxxxx() ตามที่กล่าวมาข้างต้น
ซึ่ง buffer ที่ว่านี้จะยังคงอยู่ และยังคงกินทรัพยากรระบบ
จนกว่าจะมีการเรียก method นี้ หรือจนกว่าโปรแกรม PHP จะจบการทำงาน
ดังนั้นเราควรเรียกใช้ method นี้ทุกครั้งเมื่ออ่านข้อมูลออกมาจนครบ หรือไม่ต้องการอ่านข้อมูลจาก MySQLi_Result Object นั้นๆ แล้ว
MySQLi_Result::$num_rows
จำนวนแถวที่อยู่ในผลลัพธ์
แบบ OOP (เรียกใช้ method ของ object)
กับแบบ Procedural (เรียกใช้ฟังก์ชั่น)
OOP
$result = $mysqli->query("SELECT * FROM `table`");
Procedural
$result = mysqli_query($mysqli, "SELECT * FROM `table`");
ในบทความนี้จะกล่าวถึงแบบ OOP เท่านั้น เพราะการเขียนแบบ OOP นั้นมีโอกาสที่จะเกิดความผิดพลาดน้อยกว่า
เหตุผลคือ การเขียน MySQLi แบบ Procedural จะต้องมีการส่งตัวแปร mysqli object ทุกครั้ง
พูดง่ายๆ คือต้องเขียนยาวกว่า และอาจจะสับสนได้ง่ายกว่า
และอาจจะทำงานช้ากว่า เพราะแบบหลังอาจจะเป็นแค่การเรียก method ของ object ที่ส่งไปในแบบ OOP นั่นเอง
ซึ่งจริงๆ แล้ว mysqli_query() อาจจะทำงานในลักษณะนี้
function mysqli_query(MySQLi $link, $query, $resultmode = MYSQLI_STORE_RESULT) { return $link->query($query, $resultmode); }
การเชื่อมต่อฐานข้อมูลด้วย MySQLi
ก่อนจะใช้ MySQLi นั้น ก็เหมือนกับการใช้ฟังก์ชั่น mysql_xxxxx()
คือต้องเชื่อมต่อกับ MySQL Server ก่อน ซึ่งในแบบเดิมเราใช้ mysql_connect()
แต่ในการเขียนด้วย MySQLi จะทำได้สองแบบ
1. ด้วย MySQLi::__construct() หรือการ new mysqli()
แบบนี้จะสามารถสร้าง MySQLi Object และทำการเชื่อมต่อไปได้ในคำสั่งเดียว
$mysqli = new mysqli('localhost', 'root', 'password', 'default_db_name');
$mysqli = mysqli_connect('localhost', 'root', 'password', 'default_db_name');
2. สร้าง MySQLi Object ด้วย mysqli_init() และเชื่อมต่อด้วย MySQLi::real_connect()
โดย mysqli_init() จะสร้าง MySQLi Object ให้เพื่อเอาไปใช้กับ MySQLi::options() และ MySQLi::real_connect()
ความแตกต่างกับแบบแรกคือ แบบแรกจะไม่สามารถกำหนด options ให้กับการเชื่อมต่อ
เช่น ระยะเวลา timeout, คำสั่ง SQL เริ่มต้น, ตั้งค่าการเชื่อมต่อแบบ SSL ฯลฯ
$mysqli = mysqli_init(); // การปรับแต่ง options ต้องทำก่อนการเชื่อมต่อ $mysqli->options(MYSQLI_OPT_CONNECT_TIMEOUT, 3600); // เชื่อมต่อ $mysqli->real_connect('localhost', 'root', 'password', 'default_db_name');
ดังนั้นในส่วนของการเชื่อมต่อ เราใช้ method/function ดังนี้
MySQLi::__construct()
mysqli_connect()
สร้าง MySQLi Object และเชื่อมต่อฐานข้อมูลไปในคราวเดียว
MySQLi::__construct($host, $username, $password, $dbname) mysqli_connect($host, $username, $password, $dbname)
$host ชื่อหรือ IP ของ MySQL Server เช่น 'localhost' หรือ '127.0.0.1' $username ชื่อผู้ใช้ $password รหัสผ่าน $dbname ชื่อฐานข้อมูล default ที่จะใช้กับทุกๆ query ที่อ่านค่าจากตารางโดยไม่เจาะจงฐานข้อมูล
ค่าที่คืนกลับมา
คืน MySQLi Object กลับมาเสมอ ไม่ว่าผลการเชื่อมต่อจะเป็นอย่างไร ซึ่งหากจะตรวจสอบว่าเชื่อมต่อสำเร็จหรือไม่ ต้องตรวจด้วย MySQLi::$connect_errno หรือ MySQLi::$connect_error
ตัวอย่าง
$mysqli = new mysqli('localhost', 'root', 'password', 'default_db_name'); // หรือ $mysqli = mysqli_connect('localhost', 'root', 'password', 'default_db_name'); if ($mysqli->connect_errno) { echo $mysqli->connect_error; exit; }
mysqli_init()
สร้าง MySQLi Object เพื่อใช้ในการตั้งค่าด้วย MySQLi::options() และเชื่อมต่อด้วย MySQLi::real_connect()
ค่าที่คืนกลับมา
MySQLi Object
ตัวอย่าง
$mysqli = mysqli_init();
MySQLi::real_connect()
เชื่อมต่อฐานข้อมูล โดยต้องเป็น MySQLi Object ที่สร้างขึ้นจาก mysqli_init() เท่านั้น
MySQLi::real_connect($host, $username, $password, $dbname)
$host ชื่อหรือ IP ของ MySQL Server เช่น 'localhost' หรือ '127.0.0.1' $username ชื่อผู้ใช้ $password รหัสผ่าน $dbname ชื่อฐานข้อมูล default ที่จะใช้กับทุกๆ query ที่อ่านค่าจากตารางโดยไม่เจาะจงฐานข้อมูล
ค่าที่คืนกลับมา
true หากเชื่อมต่อสำเร็จ false หากการเชื่อมต่อเกิดความผิดพลาด โดยสามารถตรวจสอบสาเหตุของความผิดพลาดได้ด้วย MySQLi::$connect_error
ตัวอย่าง
$mysqli = mysqli_init(); $mysqli->real_connect('localhost', 'root', 'password', 'default_db_name');
MySQLi::$connect_errno
MySQLi::$connect_error
เป็น property ที่บอกว่า การเรียกใช้ MySQLi::__construct() หรือ MySQLi::real_connect() นั้นมีความผิดพลาดเกิดขึ้นหรือไม่
โดย MySQLi::$connect_errno เป็นตัวเลขของ error code
ส่วน MySQLi::$connect_error จะเป็น error message
หากไม่มี error เกิดขึ้น MySQLi::$connect_errno จะมีค่าเป็น 0
ส่วน MySQLi::$connect_error จะมีค่าเป็น ''
ตัวอย่าง
$mysqli = mysqli_init(); // ใช้ @ ปิดการแสดง warning ไว้ในกรณีที่เราอยากจะแสดง error message ในแบบของเราเอง @$mysqli->real_connect('localhost', 'root', 'password', 'default_db_name'); if ($mysqli->connect_errno) { echo $mysqli->connect_error; exit; }
ผลลัพธ์อาจจะเป็นเช่นนี้
Access denied for user 'root'@'localhost' (using password: YES)
การใช้คำสั่ง SQL
เมื่อเราได้ MySQLi Object จากการเชื่อมต่อฐานข้อมูลที่สำเร็จแล้ว
ก็มาถึงการใช้งาน MySQLi Object นั้นๆ ซึ่งโดยปกติก็คือการส่งคำสั่ง SQL ไปให้ MySQL Server ประมวลผล
ในการเขียนแบบเก่าเราใช้ฟังก์ชั่น mysql_query()
แต่ในแบบใหม่ เราจะใช้ method MySQLi::query() หรือ MySQLi::real_query() และอื่นๆ
MySQLi::query()
ส่งคำสั่ง SQL ไปให้ MySQL Server ประมวลผล
MySQLi::query($query)
$query คำสั่ง SQL ไปให้ MySQL Server ประมวลผล ซึ่งควรจะ escape ด้วย MySQLi::real_escape_string()
ค่าที่คืนกลับมา
false หากเกิดความผิดพลาด ซึ่งสามารถตรวจสอบสาเหตุของความผิดพลาดได้ด้วย MySQLi::$errno และ MySQLi::$error true หากคำสั่ง SQL ที่ส่งไปเป็นคำสั่งที่ไม่คืนผลลัพธ์เป็นข้อมูลกลับมา เช่น INSERT, UPDATE, DELETE ฯลฯ MySQLi_Result Object หากคำสั่ง SQL ที่ส่งไปเป็นคำสั่งที่อ่านข้อมูลกลับมา เ่ช่น SELECT, SHOW, EXPLAIN ฯลฯ
ตัวอย่าง การ INSERT
// escape ค่าที่มาจากผู้ใช้เพื่อป้องกัน SQL Injection $_POST['username'] = $mysqli->real_escape_string($_POST['username']); $_POST['password'] = $mysqli->real_escape_string($_POST['password']); // $result จะเ็ป็น Boolean true หรือ false บอกว่าการ query นั้นๆ สำเร็จหรือไม่ $result = $mysqli->query( " INSERT INTO `users` (`username`, `password`) VALUES ('$_POST[username]', '$_POST[password]') " );
ตัวอย่างการ SELECT
// escape ค่าที่มาจากผู้ใช้เพื่อป้องกัน SQL Injection $_POST['id'] = $mysqli->real_escape_string($_POST['id']); // $result จะเป็น instance ของคลาส MySQLi_Result $result = $mysqli->query("SELECT * FROM `users` WHERE `id` = '$_POST[id]'"); // ซึ่งจะมี method ที่เกี่ยวข้องกับการดึงข้อมูล เทียบเท่ากับฟังก์ชั่นพวก mysql_fetch_xxxxx() $row = $result->fetch_assoc(); // แสดงข้อมูลแถวแรก echo $row['username'];
MySQLi_Result Object
เป็น Object ที่จะได้จากการเรียกใช้ method MySQLi::query() (และอื่นที่คล้ายคลึงกัน)
ซึ่งเป็น Object ที่มี method ในการตรวจสอบและดึงข้อมูล
กระบวนการ query และรับ result นี้ ผมขอเปรียบกับการสั่งซื้อของกับยี่ปั๊วทางโทรศัพท์
ซึ่งการ query คือการโทรไปสั่งซื้อ บอกว่าต้องการอะไร
และ result ที่ได้รับกลับคืนมาจากการ query นั้น "ยังไม่ใช่สินค้า"
แต่เป็น "รถขนสินค้าและพนักงานยกของ"
// เฮียๆ สั่งเบียร์หน่อย เอาสิงห์ กับช้างนะ รวมๆ กันมา 50 ลังล่ะกัน $result = $mysqli->query( " SELECT * FROM `stock` WHERE `type` = 'beer' AND `brand` IN ('Singha', 'Chang') LIMIT 50 " ); // เปรียบให้ $result คือรถขนสินค้า ที่ตอนนี้บรรทุกเบียร์ที่สั่งไปอยู่เต็มคันรถ // ถามขนขับรถดูซิว่าขนมากี่ลัง ครบมั้ย echo $result->num_rows; // ให้พนักงานขนของช่วยขนเบียร์ลงมาดูสักลังก่อนซิ $item = $result->fetch_assoc(); // โอเค ถูกต้อง ยกมาหมดเลยล่ะกัน $warehouse = array(); // ขนลงมาเรื่อยๆ จนกว่าจะไม่มีของให้คนแล้ว while (($item = $result->fetch_assoc())) { // ยกเบียร์เข้าไปเก็บในโกดังทีละลัง $warehouse[] = $item; } // บอกให้คนขับรถกลับไปได้แล้ว $result->free();
MySQLi_Result::fetch_xxxxx()
เป็น method ที่ใช้ดึงข้อมูลที่ได้มาจากการ query ซึ่งมีหลาย method ด้วยกัน แตกต่างตามชนิดข้อมูลที่คืนมา
MySQLi_Result::fetch_assoc() ข้อมูลที่ได้จะเป็น associative array MySQLi_Result::fetch_row() ข้อมูลที่ได้จะเป็น indexed array MySQLi_Result::fetch_array() ข้อมูลที่ได้จะเป็นทั้ง indexed array และ associative array MySQLi_Result::fetch_object() ข้อมูลที่ได้จะเป็น object
โดยปกติเราจะใช้ MySQLi_Result::fetch_assoc() เป็นหลัก
และไม่ควรใช้ MySQLi_Result::fetch_array() เพราะจะทำให้เปลืองหน่วยความจำโดยใช่เหตุ
ตัวอย่าง MySQLi_Result::fetch_assoc()
$result = $mysqli->query("SELECT * FROM `games`"); $row = $result->fetch_assoc(); print_r($row); // เข้าถึงด้วยชื่อคอลัมน์ในตาราง echo $row['title'];
ผลลัพธ์
Array ( [id] => 1 [released] => 2012-09-20 [title] => Pro Evolution Soccer 2013 [price] => 1090 ) Pro Evolution Soccer 2013
ตัวอย่าง MySQLi_Result::fetch_row()
$result = $mysqli->query("SELECT * FROM `games`"); $row = $result->fetch_row(); print_r($row); // เข้าถึงข้อมูลด้วยลำดับของคอลัมน์ในตาราง echo $row[2];
ผลลัพธ์
Array ( [0] => 1 [1] => 2012-09-20 [2] => Pro Evolution Soccer 2013 [3] => 1090 ) Pro Evolution Soccer 2013
ตัวอย่าง MySQLi_Result::fetch_array()
$result = $mysqli->query("SELECT * FROM `games`"); $row = $result->fetch_array(); print_r($row); // เข้าถึงข้อมูลได้ทั้งสองแบบ echo $row['2']; echo $row['title'];
ผลลัพธ์เป็น array ที่มี key ทั้งสองแบบ แต่ไม่ควรใช้เพราะเปลืองหน่วยความจำ (จะเห็นว่ามีข้อมูลที่ซ้ำกัน)
Array ( [0] => 1 [id] => 1 [1] => 2012-09-20 [released] => 2012-09-20 [2] => Pro Evolution Soccer 2013 [title] => Pro Evolution Soccer 2013 [3] => 1090 [price] => 1090 ) Pro Evolution Soccer 2013Pro Evolution Soccer 2013
ตัวอย่าง MySQLi_Result::fetch_row()
$result = $mysqli->query("SELECT * FROM `games`"); $row = $result->fetch_object(); print_r($row); // ต้องเข้าถึงข้อมูลในแบบ Object echo $row->title;
ผลลัพธ์เป็นชนิด Object
stdClass Object ( [id] => 1 [released] => 2012-09-20 [title] => Pro Evolution Soccer 2013 [price] => 1090 ) Pro Evolution Soccer 2013
MySQLi_Result::free()
ทำลายข้อมูลที่ query มาก่อนหน้า เพื่อคืนหน่วยความจำให้กับระบบ
ในการ query เพื่อให้ได้ MySQLi_Result Object นั้น ทุกๆ ครั้ง MySQL จะต้องเก็บผลลัพธ์ที่ได้ไว้ใน buffer ก่อน
ซึ่งอาจจะเป็นในหน่วยความจำ (RAM) หรือในฮาร์ดดิสก์
หลังจากนั้นจึงให้ผู้ใช้อ่านข้อมูลด้วย method fetch_xxxxx() ตามที่กล่าวมาข้างต้น
ซึ่ง buffer ที่ว่านี้จะยังคงอยู่ และยังคงกินทรัพยากรระบบ
จนกว่าจะมีการเรียก method นี้ หรือจนกว่าโปรแกรม PHP จะจบการทำงาน
ดังนั้นเราควรเรียกใช้ method นี้ทุกครั้งเมื่ออ่านข้อมูลออกมาจนครบ หรือไม่ต้องการอ่านข้อมูลจาก MySQLi_Result Object นั้นๆ แล้ว
ตัวอย่าง
$result = $mysqli->query("SELECT * FROM `games`"); while (($row = $result->fetch_assoc())) { // do something } $result->free();
MySQLi_Result::$num_rows
จำนวนแถวที่อยู่ในผลลัพธ์
ตัวอย่าง MySQLi_Result::fetch_row()
$result = $mysqli->query("SELECT * FROM `games` LIMIT 10"); echo $result->num_rows;
ผลลัพธ์
10
ดีมากเลยค่ะ
ตอบลบ