สังเกตว่านี่เป็นแค่เพียงมีการเรียก function ที่มีการแก้ไขตัวแปร global เพียง 1 function ยังทำให้เกิดปัญหาขนาดนี้
ถ้าหาก writeFile มีการเรียก user defined function ที่มีการแก้ไขตัวแปร $_POST สัก 5 function และ function ที่ไม่มีการแก้ไขตัวแปร $_POST อีก 5 function
มีคำถามคือ เวลาตรวจหาว่า function ไหนกันแน่ที่เป็นผู้ส่งผลกระทบกับ $_POST จะต้องค้นหาใน function กี่ function
คำตอบคือ 10 function! เพราะว่าในชื่อ function ไม่ได้ระบุว่า function ไหนเป็นผู้แก้ $_POST และ function ไหนไม่มีผลกระทบกับ $_POST
3. ถ้ามีการใช้ตัวแปร global โดยไม่วางระเบียบเอาไว้อย่างชัดเจน จะทำให้โปรแกรมหา error ได้ยาก
function foo($x){ //สมมุติเราเขียน
global $a;
$a[] = $x;
}
function bar($y){ //สมมุติเพื่อนเขียน
global $a;
$a+=$y;
}
foo(1);
foo(2);
$a = new Db();
foo(3);
bar(2);
bar(3);
bar(4);
ต่างคนใช้ตัวแปร global $a ไปทำหน้าที่เฉพาะที่ต้องการ ซึ่งเวลาใช้แยกกันก็ทำงานตามปกติ
แต่เวลาใช่รวมกันแล้วไม่มีทางใช้ร่วมกันได้เลย ถ้าจะใช่ร่วมกันก็ต้องไปแก้ที่ function ใด function หนึ่ง
ถ้ามีตัวแปร global เยอะๆ การนำกลับมาใช้ใหม่จะทำได้ยาก
เพราะนอกจากการพยายามเลี่ยงไม่ให้ function ชื่อซ้ำกันแล้ว และเลี่ยงชื่อตัวแปรในโปรแกรมไม่ให้ซ้ำกัน
ต้องไปไล่ค้นหาตัวแปร global ใน function เพื่อที่จะหลีกเลี่ยงชื่อตัวแปร global ที่อยู่ใน function นั้นอีก
ที่ยกตัวอย่างมาคือข้อเสียของการใช้ตัวแปร global ใน function ครับ ซึ่งจริงๆ มันมีมากกว่านี้อีกหลายอย่าง
แต่ไม่ใช่ว่ามันจะไม่มีข้อดีเลย แต่จะต้องวางแผนการใช้ตัวแปรให้ดี
และควรระบุจะ comment โปรแกรมว่ามีการเปลี่ยนแปลงตัวแปร global ที่ไหนบ้าง และตัวแปร global นี้ใช้งานอย่างไร
ข้อดีของการใช้ตัวแปร global
- การใช้ตัวแปร global ลดการส่ง parameter ซ้ำซ้อนในโปรแกรม
ถ้าใน 100 function มีการใช้งานตัวแปร $x ทุกครั้ง การให้ $x เป็น parameter จะทำให้ความยาวของโค้ดยาวขึ้นและอ่านยากขึ้น
เราก็อาจจะให้ $x นี้เป็น ตัวแปร global หรือไม่ก็ constant ก็ได้เพื่อให้เราสามารถเรียกใช้ function ของเราทำได้ง่ายขึ้น
การใช้ global ในโปรแกรมควรจะมีแค่ 1-2 ตัว ถ้ามีจำนวนหลายตัว ไม่ควรให้รูปแบบของชื่อเหมือนกับตัวแปร local
เช่นเราอาจตั้งชื่อให้เป็น $gSum, $gTotal, $g_array, $_gdata ฯลฯ เพื่อให้แยกแยะตัวแปรได้ง่ายขึ้น
- เร็วกว่าการส่ง parameter
การส่ง parameter โดยปกติจะมีการคัดลอกค่าไปไว้ในหน่วยความจำชั่วคราว ซึ่งจะเสียเวลาในการประมวลผลในส่วนนี้
แต่ถ้าถ้าเป็นตัวแปร global จะเป็นข้อมูลเพียงตัวเดียวไม่ต้อง copy ค่าไปไว้ที่ใหม่จึงทำงานเร็วกว่าและประหยัดพื้นที่มากกว่า
- ในโครงสร้างภาษาแบบ OOP ต่างๆ เห็นประโยชน์ของตัวแปร global จึงสร้างรูปแบบตัวแปร global ที่มีขอบเขตแคบลง
โดยเป็น global เฉพาะภายใน object นั้นๆ ที่เรียกว่า attribute หรือ property ของ object นั่นเอง
ทำให้ใน function หรือ method ต่างๆ มีการใช้ตัวแปรของ object ร่วมกันได้ไม่จำเป็นต้องส่ง parameter ไปมา
การลดขอบเขตของตัวแปร global กลายเป็นเป็นสมาชิก attribute ของ object ทำให้เราขอบเขตของ function ที่ส่งผลกับตัวแปร
แคบลงไปเป็นเพียงแค่ function ที่อยู่ในกลุ่มของ class เดียวกันเท่านั้น ที่อาจจะส่งผลกระทบกับตัวแปร
==============================
ตัวอย่าง function ที่ดี
1. input เข้าทางเดียวและ output ออกทางเดียว
- input เข้าทาง parameter
- output ออกทาง จุดคืนค่าของ function
function goodFunction($a,$b){
return $a+$b;
}
$_POST['z'] = goodFunction($_POST['x'],$_POST['y']);
การเปลี่ยนแปลงตัวแปร $_POST['z'] จะไม่ทำใน function
แต่จะแสดงออกโดยชัดเจนจาก การที่ $_POST['z'] ได้รับจาก goodFunction
ซึ่งทำให้แก้โปรแกรมได้ง่ายเพราะไม่ต้องกังวลว่าการแก้ตัวแปรจะส่งผลกับ function
เมื่อมีการแก้ไขตัวแปรก็จะทราบว่าตัวแปรไหนได้รับผลกระทบจาก function ไหนได้ทันที
ตัวอย่าง function ที่ไม่ดี
1. input เข้าหลายทาง
function badFunction($a,$b){
global $n;
return $n+$a+$b;
}
$n = 10; //ไม่แสดงออกว่ามันเป็น input ตามธรรมชาติอย่างการส่ง parameter
$_POST['z'] = badFunction($_POST['x'],$_POST['y']);
2. output ออกหลายทาง
function badFunction2($a,&$b){
$b++;
return $a+$b;
}
$a = 11;
$b = 22;
$c = badFunction2($a,$b); //ไม่แสดงออกว่ามันเป็น output ตามธรรมชาติอย่างการคืนค่าของ function
คนที่ไม่ได้เป็นผู้เขียน function จะไม่รู้เลยว่า ตัวแปร $b ได้รับผลกระทบจาก function
ตัวอย่าง function ที่พอใช้ได้แต่ไม่ค่อยดีเท่าไหร่
1. input และ output ทางเดียว แต่ะเข้าและออกในทางเดียวกัน
function increaseAll(&$a,&$b,&$c){
$a++;
$b++;
$c++;
}
มี input และ output ทางเดียว แต่ output ไม่เป็นธรรมชาติ
ควรจะเขียนและใช้งาน function รูปแบบนี้เท่าที่จำเป็น
ในการเขียนโปรแกรมแบบ OOP มักจะเทคนิคการส่ง parameter เป็น object อยู่
ซึ่งเป็นเทคนิคที่คล้ายๆ กับ function increaseAll นี้คือการส่งแบบ reference
ทำให้ สมาชิก attribute ในตัวแปร object จะถูกเปลี่ยนแปลงใน function ได้ด้วย
ข้อดีของการส่ง object แบบ reference นี้ก็คือลดปริมาณการคัดลอกข้อมูลสมาชิกของ object
อย่างไรก็ตามก็ไม่ควรใช้เทคนิคนี้พร่ำเพรื่อ เพราะเป็นการเขียน function ในรูปแบบที่อ่านเข้าใจยาก
ควรเขียน function แบบนี้ เมื่อวิเคราะห์แล้วว่ารูปแบบนี้ เป็นรูปแบบที่เหมาะสมมากกว่ารูปแบบ function อื่นๆ