เปรียบเทียบความเร็วในการแปลตัวเลข 0-9 ให้เป็นภาษาอังกฤษ
จากโจทย์ หลายคนคงคิดถึง if และ switch case ประมาณนี้
โดยการใช้ if else
if ($value == 0) {
echo "Zero\n";
} elseif ($value == 1) {
.....
} else {
// ไม่พบ
echo $value."\n";
}
หรือการใช้ switch case
switch ($value) {
case 0:
echo "Zero\n";
break;
case 1:
.....
default:
// ไม่พบ
echo $value."\n";
break;
}
ซึ่งโดยทั่วๆ เราจะมองว่ามันเป็นคำสั่งพื้นฐาน
ในแง่ความเร็ว หลายๆคนคงเคยได้ยินมาว่า switch case นั้นเร็วกว่า if else ซึ่งจากการที่ผมทดสอบมันก็เป็นแบบนั้นแหละ แต่มันมีปัญหาอยู่อย่างหนึงของการใช้ if else และ switch case คือในกรณีที่เงื่อนไขมันมากคำสั่งก็จะยาวและอ่านยากไปด้วยตามมา (ดูได่จากโค้ดด้านล่าง) แล้วจะมีวิธีไหนที่จะลดความซับซ้อนของโค้ดลงได้
ผมขอเสนออีกวิธีหนึ่ง ด้วยการใช้ isset
// ตัวแปรแอเรย์เก็บตัวเลขในภาษาอังกฤษ
$numbers = array(
0 => 'Zero',
1 => 'One',
....
9 => 'Nine',
);
if (isset($numbers[$value])) {
// พบ
echo $numbers[$value]."\n";
} else {
// ไม่พบ
echo $value."\n";
}
โค้ดด้านบนเราจะสร้างแอเรย์เก็บ ตัวเลข 0-9 พร้อมกับคำแปลตามโจทย์ จากนั้นใช้ isset ในการทดสอบว่ามีตัวแปรที่ต้องการหรือไม่ ถ้ามีก็คืนค่าตัวแปรนั้นๆ ออกมา โค้ดสั้นและง่ายขึ้นเห็นๆ (คำสั่งแอเรย์ที่สร้างอาจดูยาวอยู่นะครับ แต่มันก็อ่านง่าย รวมถึงแก้ไขง่ายขึ้นเยอะเลย) ส่วนความเร็วของคำสั่งทั้งสามรูปแบบ ดูได้ท้ายบทความเลย (สามารถนำโค้ดไปทดสอบได้ในเครื่องตัวเอง)
// จำนวนรอบการทดสอบ ผลลัพท์เฉลี่ยจากค่านี้
$count = 100;
// แอเรย์เก็บผลลัพท์
$ret = array(0, 0, 0);
// ตัวเลขที่ต้องการแปล 0 - 11
$wants = range(0, 11);
// ตัวแปรแอเรย์เก็บตัวเลขในภาษาอังกฤษ
$numbers = array(
0 => 'Zero',
1 => 'One',
2 => 'Two',
3 => 'Three',
4 => 'Four',
5 => 'Five',
6 => 'Six',
7 => 'Seven',
8 => 'Eight',
9 => 'Nine',
);
for ($m = 0; $m < $count; $m++) {
$start = microtime(true);
foreach ($wants as $value) {
if (isset($numbers[$value])) {
// คืนค่าตัวเลขในภาษาอังกฤษ
echo $numbers[$value]."\n";
} else {
// ไม่พบ
echo $value."\n";
}
}
$ret[0] += microtime(true) - $start;
}
usleep(10240);
for ($m = 0; $m < $count; $m++) {
$start = microtime(true);
foreach ($wants as $value) {
if ($value == 0) {
echo "Zero\n";
} elseif ($value == 1) {
echo "One\n";
} elseif ($value == 2) {
echo "Two\n";
} elseif ($value == 3) {
echo "Three\n";
} elseif ($value == 4) {
echo "Four\n";
} elseif ($value == 5) {
echo "Five\n";
} elseif ($value == 6) {
echo "Six\n";
} elseif ($value == 7) {
echo "Seven\n";
} elseif ($value == 8) {
echo "Eight\n";
} elseif ($value == 9) {
echo "Nine\n";
} else {
// ไม่พบ
echo $value."\n";
}
}
$ret[1] += microtime(true) - $start;
}
usleep(10240);
for ($m = 0; $m < $count; $m++) {
$start = microtime(true);
foreach ($wants as $value) {
switch ($value) {
case 0:
echo "Zero\n";
break;
case 1:
echo "One\n";
break;
case 2:
echo "Two\n";
break;
case 3:
echo "Three\n";
break;
case 4:
echo "Four\n";
break;
case 5:
echo "Five\n";
break;
case 6:
echo "Six\n";
break;
case 7:
echo "Sever\n";
break;
case 8:
echo "Eight\n";
break;
case 9:
echo "Nine\n";
break;
default:
echo $value."\n";
break;
}
}
$ret[2] += microtime(true) - $start;
}
usleep(10240);
echo '<br><br>Current PHP version: '.phpversion().'<br>';
echo ($ret[0] / $count).' (isset)<br>';
echo ($ret[1] / $count).' (if else)<br>';
echo ($ret[2] / $count).' (switch case)<br>';
ผลการทดสอบ Benchmark ของคำสั่งแต่ละรูปแบบ
- ผลการทดสอบเฉลี่ยผมให้ isset ชนะ ทั้งในแง่อ่านง่ายแก้ไขง่าย และทางด้านความเร็ว
- ผลการทดสอบจริงอาจแตกต่างจากนี้เนื่องจากเวอร์ชั่นของ PHP (PHP แต่ละเวอร์ชั่นอาจได้ผลลัพท์แตกต่างจากนี้ เนื่องจากการ Optimize ของ PHP เอง)
- ผลการทดสอบในแต่ละรอบไม่ได้ให้ผลเหมือนกันทุกครั้ง และ isset ไมได้เร็วกว่า switch case ซะทุกครั้ง โดยมี if else รั้งท้าย หากใครต้องการเห็นผลทดสอบจริงๆ แนะนำให้นำโค้ดไปรันทดสอบบนเครื่องตัวเอง
- การทดสอบในตัวอย่าง กระทำกับแต่ละคำสั่งเป็นจำนวน 100 รอบ (ดูได้จากโค้ด) แล้วคืนค่าเวลาเฉลี่ยของแต่ละรูปแบบออกมา