ขอแนะนำบทความหน่อยนะครับ เรื่อง การใช้ตัวแปรในสตริง (String Interpolation) ครับ
บทความนี้เขียนขึ้นจากการสังเกตเห็นสมาชิกในไทยครีเอทหลายๆ คนนิยมและบอกต่อให้ใช้การเชื่อมต่อสตริง
แทนที่จะใช้ตัวแปรในสตริง ทั้งๆ ที่ความสามารถนี้เป็นอะไรที่ทำให้ PHP (หรือภาษาอื่นที่มีความสามารถนี้เช่น Perl และ Ruby) มีจุดเด่น
ผมเขียนเป็นบทความไว้แล้ว แต่ขอโพสต์เป็นกระทู้ด้วยครับ เผื่อจะได้พูดคุยแลกเปลี่ยนความคิดเห็นกัน
บ่อยครั้งที่ผมเห็นหลายๆ คนนิยมเขียนโค้ดลักษณะนี้
$sql = "SELECT * FROM table";
$sql .= "WHERE id = '" . $id . "'";
ซึ่งก็มาจากการแนะนำบอกต่อกันมาว่าแบบนี้ดี ทำให้อ่านง่าย เห็นชัด
อันนี้ผมไม่เถียงครับ แต่ผลที่ตามมาในหลายๆ กระทู้ที่ผมสังเกต
วิธีเขียนแบบนี้นี่แหละที่ทำให้มือใหม่หลายๆ คนออกมาตั้งกระทู้ถามว่า "ฉันเขียนผิดตรงไหน"
เพราะการเขียนแบบเชื่อมต่อสตริง ทำให้เกิดข้อผิดพลาดได้ง่าย หากไม่ใช่คนที่คุ้นเคยกับ PHP
หรือช่างสังเกต อาจจะไม่รู้เลยว่าผิดตรงไหน อะไรยังไง
เช่น
$sql = "UPDATE table SET name = '" . $name . "', color = '" . $color . "'";
$sql .= "type = '" . $type . "' WHERE id = '" . $id . "'";
ลองหาที่ผิดดูครับ
วิธีที่เรียบง่ายกว่า แต่ไม่นิยมใช้กันเพราะ "ความเชื่อ"
เคยเป็นที่ถกเถียงกันในเว็บนักพัฒนาต่างประเทศว่าการเชื่อมต่อสตริงนั้น "ทำงานได้เร็วกว่า" การใช้ตัวแปรในสตริง
แต่หลังจากนั้นก็มีการทดสอบจนได้ผลว่า การเชื่อมต่อสตริงทำงานเร็วกว่าในกรณีที่ "มีการเชื่อมต่อแค่ครั้งเดียว"
แต่ถ้ามีมากกว่านั้นการใช้ตัวแปรในสตริงจะทำงานได้เร็วกว่า
$a = "Hello World $str";
$b = "Hello World " . $str; // เร็วกว่า
$a = "Hello World $str !!!";
$b = "Hello World " . $str . " !!!"; // แต่แบบนี้ไม่
และยิ่งไปกว่านั้น หากมีตัวแปรมากขึ้นเท่าไหร่ ความเร็วการทำงานก็จะต่างกันมากขึ้นเท่านั้น
$sql = "UPDATE table SET name = '" . $name . "', color = '" . $color . "'";
$sql .= ", type = '" . $type . "' WHERE id = '" . $id . "'";
$fastSQL = "UPDATE table SET name = '$name', color = '$color', type = '$type' WHERE id = '$id'"; // แบบนี้เร็วกว่ามาก
และความเชื่ออีกอย่างคือ คิดว่าการเชื่อมต่อสตริงทำให้อ่านง่ายกว่า
ลองมาดูกันชัดๆ ครับ
การเชื่อมต่อสตริง
$sql = "INSERT INTO table";
$sql .= "(first_name, last_name, username, password)";
$sql .= "VALUES ('" . $first_name . "','" . $last_name . "'"
$sql .= ",'" . $username . "','" . $password . "')";
การใช้ตัวแปรในสตริง
$sql = "
INSERT INTO table
(first_name, last_name, username, password)
VALUES
('$first_name','$last_name','$username','$password')
";
สำหรับคนอื่นผมไม่รู้ แต่สำหรับผมเองแล้ว แบบหลังอ่านและเขียนง่ายกว่าเยอะ (ทำงานได้เร็วกว่ามากด้วย)
อีกเหตุผลที่ไม่นิยมใช้ตัวแปรในสตริง อาจเป็นเพราะคนส่วนใหญ่ไม่เข้าใจรูปแบบการใช้
อีกเหตุผลที่ผมเดาเอาคือ เพราะไม่เข้าใจการใช้งานที่ถูกต้อง เลยต้องเปลี่ยนไปใช้การเชื่อมต่อสตริง
ผมเชื่อว่าหลายๆ คนต้องเคยมีปัญหาแบบนี้
echo "Test $item[0]['name']";
แล้วแสดงผลไม่ได้ตามต้องการ อาจจะออกเป็น Array แล้วไม่เข้าใจว่าเกิดอะไรขึ้น
หรือ
echo "Test $item['name']";
แล้วเกิด Error
Parse error: syntax error, unexpected T_ENCAPSED_AND_WHITESPACE
ทั้งๆ ที่ใช้ echo "Test " . $item['name']; แบบนี้ได้ จึงทำให้เปลี่ยนไปใช้การเชื่อมต่อสตริง
และทำให้เกิดรูปแบบการเขียนโปรแกรม PHP ที่ไม่ดีขึ้นมาอีก 1 อย่างคือ
การนิยมย้ายค่าตัวแปรจาก array ให้เป็นตัวแปรเดี่ยวๆ ก่อนนำไปใช้งาน
โดยที่ไม่ได้เปลี่ยนแปลงค่าของมัน (เช่น escape หรือคำนวณเป็นค่าอื่น)
ใช้การเขียนแบบนี้เพียงเพื่อให้ใช้ในสตริงได้ง่ายๆ
$id = $_POST['id'];
$name = $_POST['name'];
$address = $_POST['address'];
$sql = "INSERT INTO users VALUES ('$id', '$name', '$address')";
ซึ่งเป็นวิธีการเขียนที่สิ้นเปลืองทั้งเวลา และทรัพยากร (มีตัวแปรในหน่วยความจำเยอะแยะไปหมด)
ทั้งๆ ที่ควรเขียนแบบนี้
$sql = "INSERT INTO users VALUES ('$_POST[id]', '$_POST[name]', '$_POST[address]')";
มาทำความเข้าใจรูปแบบโดยละเอียดกัน
การใช้ตัวแปรในสตริง (String Interpolation) ในภาษา PHP นั้น
จะเป็นการใช้สัญลักษณ์ $ ในสตริงแบบ Double Quote หรือ HereDoc
$a = 123;
$b = 456;
$c = 789;
echo "a = $a, b = $b, c = $c\n";
echo <<<DOC
a = $a
b = $b
c = $c
DOC;
แบบที่ 1 ใช้ชื่อตัวแปรตรงๆ
$a = 555;
echo "a is $a.";
แบบที่ 2 อ้างถึงสมาชิกใน array 1 มิติ โดยใช้ index
$a = array(123, 456, 789);
echo "สมาชิกตัวแรกของ a คือ $a[0] ตัวที่ 2 คือ $a[1] และสุดท้ายคือ $a[2]";
และต้องเป็นตัวเลขจำนวนเต็มเท่านั้น เป็นจุดทศนิยมไม่ได้ เพราะจะเกิด Error
$a = array(123, 456, 789);
echo "สมาชิกตัวแรกของ a คือ $a[0] ตัวที่ 2 คือ $a[1.0] และสุดท้ายคือ $a[2.0]";
// Parse error: syntax error, unexpected '.'
แบบที่ 3 อ้างถึงสมาชิกใน array 1 มิติ โดยใช้ key
รูปแบบคือ $array[key]
$ages = array('david' => 45, 'sally' => 20, 'john' => 31);
echo "David is $ages[david] years old\n";
echo "Sally is $ages[sally] years old\n";
echo "John is $ages[john] years old\n";
โดย key นั้นต้องไม่มี ' ล้อมรอบ และไม่มีช่องว่างหรือเครื่องหมายอื่นๆ นอกจากตัวอักษร
$stages = array('Level 1' => 'Forest');
echo "Welcome to stage 1 $stages[Level 1] !!!"; // Parse error: syntax error, unexpected T_ENCAPSED_AND_WHITESPACE
แบบที่ 4 อ้างถึงสมาชิกใน array หลายมิติ หรืออ้างถึงสมาชิกที่ key มีช่องว่างและตัวอักษรพิเศษ
รูปแบบคือ {$array['key1']['key2']}
สังเกตดูนะครับ เมื่อไหร่ที่เราใช้รูปแบบนี้ เราต้องล้อมรอบ key ที่เป็นสตริงด้วย ' (แต่ index ไม่ต้อง)
$users = array(
array(
'name' => 'Jack',
'MAC address' => '01:23:45:67:89:AB',
),
array(
'name' => 'Mike',
'MAC address' => '51:47:DF:EE:4C:13',
),
);
echo "User 1: {$users[0]['name']} - {$users[0]['MAC address']}\n";
echo "User 2: {$users[1]['name']} - {$users[1]['MAC address']}\n";
สำหรับการอ้างถึงตัวแปรในสตริงในแบบนี้ มันก็เหมือนกับการเชื่อมต่อสตริงนั่นแหละครับ เพียงแต่เขียนสั้นและอ่านง่ายกว่ามาก
ลองเปรียบเทียบดู
$users = array(
array(
'name' => 'Jack',
'MAC address' => '01:23:45:67:89:AB',
),
array(
'name' => 'Mike',
'MAC address' => '51:47:DF:EE:4C:13',
),
);
// แบบเชื่อมต่อสตริง
echo "User 2: " . $users[0.5 + 0.5]['name'] . " - " . $users[floor(0.3)]['MAC' . ' address'] . "\n";
// แบบนี้ไม่ต้องเปิดปิดสตริงให้เสียเวลา ลดความความเสี่ยงที่จะเกิดความผิดพลาดด้วย
echo "User 2: {$users[0.5 + 0.5]['name']} - {$users[floor(0.3)]['MAC' . ' address']}\n";
หวังว่าบทความนี้คงจะมีประโยชน์บ้างนะครับTag : PHP
ประวัติการแก้ไข 2013-02-11 10:43:16
Date :
2013-02-11 10:39:24
By :
cookiephp
View :
920
Reply :
14
เริ่ด เจ๋ง สวดยอดเลย ลวดเพ่ เอาไป 10 like (วันนี้ให้คะแนนไปแล้ว ให้ซ้ำไม่ได้)
Date :
2013-02-11 10:53:14
By :
apisitp
ขอบคุณครับ อิอิ
Date :
2013-02-11 12:21:58
By :
cookiephp
ขอบคุณมากครับ
Date :
2013-02-11 20:55:52
By :
cookiephp
ขอเสริมอีกหน่อยครับ เราสามารถนำอาร์เรย์มาเขียนไว้ใน string ได้อีกแบบ เผอิญผมชอบใช้ลักษณะนี้
เพราะมันจะดูเด่นและสังเกตได้ง่ายกว่า
$data["docno"] = "INV56020001";
$data["custname"] = "Mr.Urvin Montana";
echo "{$data["custname"]} : {$data["docno"]}";
Date :
2013-02-11 22:45:04
By :
sakuraei
อีกบทความครับ หวังว่าจะมีประโยชน์บ้าง
มาทำความเข้าใจ isset() และ empty() ว่ามันมีการทำงานและประโยชน์อย่างไร
isset() ใช้เพื่อตรวจสอบว่า "ตัวแปรนั้นๆ ได้ถูกกำหนดขึ้น และมีค่าที่ไม่ใช่ null หรือไม่"
$a = 'Hello World';
$c = null;
$d = false;
isset($a); // true เพราะมีค่าที่ไม่ใช่ null
isset($b); // false เพราะไม่มีตัวแปร $b อยู่
isset($c); // false เพราะมีค่าเป็น null
isset($d); // true เพราะมีค่าที่ไม่ใช่ null
ซึ่งใช้ตรวจสอบเฉพาะตัวแปรเท่านั้น หากใส่อย่างอื่นลงไป จะเกิด Parse error
isset($a); // ตัวแปรเดี่ยวๆ OK
isset($a[0][1][2]); // ตัวแปร array ที่มีการเข้าถึงสมาชิก OK
isset($a + 1); // อันนี้ไม่ใช่ตัวแปร แต่เป็น expression จะทำให้เกิด Parse error
isset(htmlspecialchars($a)); // อันนี้ไม่ใช่ตัวแปร แต่เป็น function call จะทำให้เกิด Parse error
isset($a[1 + 1]); // ตัวแปร array ที่มีการเข้าถึงสมาชิกด้วย expression OK
isset($a[floor(5.5)]); // ตัวแปร array ที่มีการเข้าถึงสมาชิกด้วย function call OK
ส่วน empty() ใช้เพื่อตรวจสอบว่า "ตัวแปรนั้นๆ ยังไม่ได้ถูกกำหนดขึ้น หรือมีค่าที่ว่างเปล่า หรือไม่"
พูดง่ายๆ คือตรวจว่า มีค่าอยู่หรือไม่
ซึ่งรูปแบบของ "ค่าที่ว่างเปล่า" หรือ "ไม่มีค่า" นี้ได้แก่
null
false
0
'' (สตริงว่าง)
'0' (สตริง 0)
array() (array ที่ไม่มีสมาชิกใดๆ อยู่)
empty() นั้นก็เหมือนกับ isset() ใช้ตรวจสอบเฉพาะตัวแปรเท่านั้น
$a = 'Hello World';
$c = '';
$d = array();
empty($a); // false เพราะมีค่าที่ไม่ใช่ค่าที่ว่างเปล่า
empty($b); // true เพราะไม่มีตัวแปร $b อยู่
empty($c); // true เพราะมีค่าเป็นสตริงว่าง
empty($d); // true เพราะมีค่าเป็น array ที่ว่างเปล่า
isset() สามารถตรวจสอบตัวแปรได้ทีละหลายๆ ตัว แต่ empty() ไม่
ซึ่งจะให้ผลเป็นจริงก็ต่อเมื่อ ตัวแปรทุกตัวที่ตรวจสอบนั้นได้ถูกกำหนดขึ้น และมีค่าที่ไม่ใช่ null
$a = 1;
$b = 2;
$c = 3;
isset($a, $b, $c); // true เพราะทุกตัวมีค่าที่ไม่ใช่ null
isset($a, $b, $c, $d); // false เพราะ $d ยังไม่ถูกกำหนดขึ้น
$c = null;
isset($a, $b, $c); // false เพราะ $c เป็น null
empty($a, $b, $c); // Parse error เพราะ empty() ตรวจตัวแปรได้ทีละตัว
นอกจากการใช้เพื่อประโยชน์ข้างต้นแล้ว จะใช้เพื่ออะไรได้อีก และทำไมถึงควรใช้?
โดยปกติการเขียนโปรแกรมเพื่อเก็บสถานะจริงเท็จ เพื่อตรวจสอบว่าเงื่อนไขเป็นจริงหรือไม่ในภายจะทำในลักษณะนี้คือ
ประกาศตัวแปรขึ้นมา 1 ตัว เพื่อเก็บสถานะนั้น
$done = false;
และในส่วนของโปรแกรม อาจจะมีการทำงานที่กำหนดให้ตัวแปรนี้มีค่าที่ให้ผลเป็นจริงเมื่อตรวจสอบ
$done = true;
และหลังจากนั้นเราก็จะตรวจสอบค่าของตัวแปรนี้ และทำอะไรบางอย่างหากเงื่อนไขเป็นจริง
if ($done) {
// do something
}
ซึ่งหากมีเงื่อนไขหรือสถานะหลายอย่าง ก็ต้องประกาศตัวแปรหลายตัว
$sent = false;
$saved = false;
$cancelled = false;
ในกรณีนี้เราสามารถใช้ isset() เพื่อทำให้ทุกอย่างง่ายขึ้น
เพราะ isset() ตรวจสอบการมีอยู่ของตัวแปร ดังนั้นจึงไม่จำเป็นต้องประกาศตัวแปรก่อนที่จะตรวจสอบ
เราจึงสามารถใช้ isset() ในการตรวจสอบสถานะอะไรบางอย่างได้โดยที่ไม่ต้องประกาศตัวแปรไว้ก่อน
if (isset($sent)) {
// do something
}
if (isset($saved)) {
// do something
}
if (isset($cancelled)) {
// do something
}
// ก่อนหน้านี้จะมีการสร้างตัวแปร $sent, $saved, $cancelled หรือไม่นั้น ไม่สำคัญ
// แต่หากมีการกำหนดให้ตัวแปรเหล่านี้มีค่าที่ไม่ใช่ null เงื่อนไขก็จะเป็นจริงทันที
// ทำให้ประหยัดหน่วยความจำที่จะต้องใช้ไปกับตัวแปรเหล่านี้
ความเร็วในการทำงานล่ะ เรียกใช้ฟังก์ชั่น isset()/empty() เยอะแยะมากมายในโปรแกรมแบบนี้จะไม่ทำให้ช้าหรือ?
คำตอบคือไม่เลยครับ
เพราะ isset()/empty() เป็นโครงสร้างภาษา (Language Construct) ไม่ใช่ฟังก์ชั่น (ถึงแม้จะมีรูปร่างหน้าตาเหมือนฟังก์ชั่น)
และแม้จะใช้การตรวจสอบตัวแปรแบบปกติ ก็ไม่ได้เร็วไปกว่า isset()/empty() เท่าไหร่เลย
$a = true;
$t = microtime(true);
for ($i = 0; $i < 1000000; ++$i) {
if (!$a) {
}
}
echo microtime(true) - $t . "<br />\n";
$t = microtime(true);
for ($i = 0; $i < 1000000; ++$i) {
if (empty($a)) {
}
}
echo microtime(true) - $t . "<br />\n";
นอกจากนี้เรายังสามารถใช้ isset() ในการตรวจสอบว่า array หรือสตริงมีขนาดน้อยกว่า หรือมากกว่าที่กำหนดหรือไม่ ซึ่งทำงานได้เร็วกว่าการใช้ฟังก์ชั่นเพื่อตรวจสอบ
// ปกติเราคงจะตรวจสอบความยาวสตริงด้วย strlen()
if (strlen($str) > 100) { // ตรวจสอบว่าความยาวมากกว่า 100 หรือไม่
echo "ยาวเกินไป";
}
// แต่เราก็สามารถใช้ isset() ตรวจสอบได้เหมือนกัน ซึ่งทำงานได้เร็วกว่า
if (isset($str[100])) { // ตรวจสอบว่ามีตัวอักษรที่ 101 ถูกกำหนดไว้แล้วหรือยัง (ตำแหน่งตัวอักษรเริ่มต้นที่ 0)
echo "ยาวเกินไป";
}
Date :
2013-02-15 00:32:51
By :
cookiephp
น้องเปรม เข้าไปที่หน้าแรกสมาชิกของตัวเอง แล้วเข้าไปที่เขียนบทความเลยครับ.....เขียนไว้เยอะ ๆ เลย
Date :
2013-02-15 00:42:02
By :
apisitp
เขียนแล้วครับ แต่ก็เอามาโพสต์ในนี้ด้วยไงครับ เพราะผมว่า คนไม่ค่อยรู้หรอกว่ามีบทความมาใหม่ ส่วนใหญ่คงพุ่งเข้ามาในนี้เลย
Date :
2013-02-15 00:50:11
By :
cookiephp
เดียวจะ Approve ให้ครับ
Date :
2013-02-15 06:43:28
By :
mr.win
รอคุณวินตรวจสอบ อิอิ
Date :
2013-02-17 20:10:21
By :
cookiephp
Load balance : Server 04