PHP by &Referrence

เอาสักหน่อยละกันครับ คือผมมีช่วงนึงที่ไม่เข้าใจว่า $test = &test(); หรือ $foo = &$bar; คืออะไร(รู้สึกว่าการเขียนลักษณะนี้จะกลายเป็น trend ไปซะแล้ว) และคิดว่าคงมีอีกหลายคนที่ยังไม่เข้าใจ มาวันนี้ผมจะขออธิบายสั้นๆเพื่อไขข้อสงสัยให้เพื่อนๆได้เข้าใจกันนะครับ

ตาม title เลยครับ จากที่กล่าวมา $test = &test(); หรือ $foo = &$bar;
จะเห็นว่ามี & มันก็คือ Reference ซึ่งจะคล้ายกับตัวแปร Pointer ในภาษาอื่น (เริ่มgetๆ…. ;) ) และข้อดีของการใช้ reference ก็คือประหยัดหน่วยความจำ (แต่ใช้เยอะแล้วมึน) เพราะแทนที่ว่าจะ copy ค่าของตัวแปรไปเราก็สามารถใช้ reference แทนได้เลย

ตัวอย่าง

$foo = 1;
$bar = &$foo;
$bar++;
var_dump($foo,$bar);//foo = 2 ,bar = 2  **$foo จะเปลี่ยนตาม $bar

//ลอง foo บ้าง
$foo++;
var_dump($foo,$bar);//foo = 3,bar = 3 **$foo เปลี่ยน $bar ก็เปลี่ยน

//unset
unset($bar); //จะลบ เฉพาะ $bar , $foo จะไม่ถูก unset ด้วย
var_dump($foo,$bar); //foo = 2, bar = NULL

ถ้าเขียนปกติ

$foo = 1;
$bar = $foo;
$bar++;
var_dump($foo,$bar); //foo =1,bar = 2 (ไม่เหมือนกัน)

Return By Reference

ในเวลา เดียวกัน ณ อีกที่แห่งนึงก็มี Pass By Reference -*- ซึ่งมันก็คือ function ที่ return reference กลับมานั่นเอง(อ้อ….Get มั้ยครับถ้า get ไม่เล่าต่อนะ -*-)
และ function นี่จะ return 0;return 1;return ‘test’; ไม่เพราะไม่ได้เป็นตัวแปร ต้อง return $ตัวแปร; เท่านั้นครับ
วิธีการเขียนก็คือ

function &foo()
{
   $bar = 1;
   return $bar;
}

อะไรประมาณนี้ครับ ในการใช้จริงจาก function ข้างต้นจะเห็นว่า return = 1; ชัวอยู่แล้ว แล้วจะเขียนเป็น return 1; แทนไม่ได้นะครับ เพราะ function นี้เป็น return by reference
*return 1;ได้ครับแต่จะมี error E_NOTICE โผล่มาถ้าหากว่าเปิด error_reporting(E_ALL); หรือ E_NOTICE ไว้ครับ ซึ่ง error ประเภทนี้ดูเหมือนจะจิ๊บๆไม่สำคัญ แต่หากละเลยอาจจะทำให้โปรแกรม/สคริป ของเราไม่ทำงานอย่างที่เราต้องการได้ครับ เพราะตัวแปรที่เป็น NULL หรือ undefined โผล่มาจากไหนไม่ทราบ
* ฉนั้นให้สร้างมาตรฐานของตัวเองขึ้นมาครับว่าต้องเปิด error_reporting(E_ALL); ทุกครั้ง แล้วใช้ if(!empty($var)){} แทน if($var){} ถ้าเกิดว่ามีปัญหาตอน debug เราจะหาจุดที่มีปัญหาเจอได้ง่ายกว่า

เอาหละหลังจากพาไปเกือบออกทะเล ก็กลับมา ณ ที่แห่งนั้น กันต่อครับ
จาก function ข้างต้น &foo จะดู simple มากถ้าหากเอาไปใช้จริงคงเป็นไปไม่ได้ถ้าจะใช้อย่างนั้น
ผมเลยจะขอยกตัวอย่างอีกสักตัวอย่างละกันครับ


Class Foo
{
	public $val = 0;
	function &getVal()
	{
		return $this->val;
	}
}

$foo = new Foo();
$val = &$foo->getVal();

//ลองเปลี่ยน ค่า $foo->val
$foo->val = 2;
var_dump($val,$foo->val); // ทั้ง $val และ $foo->val มีค่าเท่ากัน

//ลองเปลี่ยนค่า $val ดูบ้าง
$val = 3;
var_dump($val,$foo->val); // $foo->val ก็เป็น 3 เหมือนกับ $val 

unset($val);
var_dump($val,$foo->val); // $foo->val จะไมถูก unset และ $val จะ = NULL * บรรทัดนี้จะ error E_NOTICE: undefined $val

มาถึงตรงนี้คงจะมีคำถามแน่ถ้าหากว่า $val = $foo->getVal(); (ไม่ใส่ & นำ)หละ มันก็เท่ากับว่า เรียกใช้ method แบบปกติ แค่ copy ค่าตัวแปรมาเฉยๆครับ

…โอ้ย เริ่มยาวครับ(สันหลัง)…

มาอีกที่นึงจะมี

Pass By Reference

Pass by Reference การใช้งานก็จะคล้ายจะ return by reference ครับ แต่เปลี่ยนจากการ return เป็นการส่งตัวแปรไปแทนครับ

function increase(&$bar)
{
	$bar++;
}
$val = 1;
increase($val);
var_dump($val); //2

บ้างครั้ง function ทั่วไปที่เราเขียน แค่ค่า return,การส่งผ่านตัวแปร แบบปกติไม่สามารถทำได้(ดีพอ) การใช้ pass by reference จะเป็นอีกทางเลือกหนึ่งที่ไม่ควรมองข้ามครับ (และก็สามารถ ลดหน่วยความจำได้ด้วย) โดยเฉพาะ Recursive function ที่มีการอ้างถึงตัวแปรอื่น (อย่างเช่น Class Walker ที่ใช้ในการ list comment แบบ nested)

จบครับ By ExpertDuck เอ้ย By &Reference ครับ ฮ่าๆ :P

ผิดพลาดตรงไหนขออภัยนะครับ ผมเองก็ยังโง่อยู่

ปล. แค่อยากแชร์ครับ ไม่ได้เป็นอาจารย์สอนที่ไหน – -*