บทนำสู่อ็อบเจ็กต์และการอ้างอิงในหน่วยความจำ PHP
เผยแพร่แล้ว: 2022-03-11ขั้นแรก ฉันร่างบทความนี้ในขณะที่ศึกษาการรับรอง PHP เพื่อพยายามทำความเข้าใจวิธีที่ PHP จัดการตัวแปรและอ็อบเจกต์ในหน่วยความจำให้ดีขึ้น หลังจากการค้นคว้าหลายครั้ง ฉันตระหนักว่าการค้นหาคำตอบสำหรับคำถามของฉันนั้นไม่ง่าย ดังนั้นเมื่อฉันทำเสร็จแล้ว ฉันจึงตัดสินใจจัดทำเอกสารข้อมูลเพื่อให้ผู้คนสามารถค้นหาคำตอบทั้งหมดได้ในที่เดียว
ในบทความนี้ ผมจะพูดถึงวิธีควบคุมการอ้างอิงอ็อบเจกต์และตัวแปรในหน่วยความจำ เนื่องจากเป็นประเด็นที่อาจทำให้เกิดการอภิปรายและความคิดเห็นที่แตกต่างกัน คำถามหนึ่งที่ต้องไตร่ตรองคือ: "โดยค่าเริ่มต้น วัตถุถูกส่งผ่านโดยการอ้างอิงหรือโดยการคัดลอกใน PHP หรือไม่" ฉันจะพูดถึงก่อนว่าการอ้างอิงใดที่ ไม่ได้ อยู่ใน PHP; ประการที่สอง ฉันจะพูดถึงสิ่งที่พวก เขา และสุดท้าย ฉันจะตรวจสอบว่าตัวรวบรวมขยะทำงานอย่างไรใน PHP
PHP สร้างวัตถุในหน่วยความจำอย่างไรเมื่อดำเนินการคำสั่งเช่น $a = new Foo(); ? ปัจจุบันหน่วยความจำไม่แพงและจำกัดทรัพยากรอย่างที่เคยเป็นมา อย่างไรก็ตาม ยังคงเป็นสิ่งสำคัญสำหรับนักพัฒนา PHP ที่ดีที่จะรู้และเข้าใจว่าตัวแปรและอ็อบเจ็กต์ได้รับการจัดการภายในอย่างไรระหว่างการดำเนินการของแอปพลิเคชัน
วัตถุและการอ้างอิงใน PHP
หลายคนบอกว่า ในหนังสือ PHP และออนไลน์—ว่าอ็อบเจกต์ใน PHP นั้นส่งผ่านโดยการอ้างอิงตามค่าเริ่มต้น บางคนบอกว่าวัตถุใน PHP ได้รับการจัดสรรโดยการคัดลอก ในการหาว่าคำสั่งใดถูกต้อง ก่อนอื่นเราต้องวิเคราะห์ว่าอะไรคือ (และอะไรไม่ใช่) ข้อมูลอ้างอิงใน PHP
อะไร ไม่ อ้างอิงใน PHP?
สำคัญกว่าการรู้ว่าการอ้างอิงใดใน PHP คือการรู้ว่า ไม่ใช่ สิ่งอ้างอิง ใน PHP การอ้างอิงไม่ใช่ตัวชี้แบบ C คุณไม่สามารถดำเนินการเลขคณิตด้วยการอ้างอิงได้เหมือนกับที่คุณสามารถทำได้ด้วยพอยน์เตอร์ C ทำไม? เนื่องจากไม่เหมือนกับในภาษา C การอ้างอิง PHP ไม่ใช่ที่อยู่หน่วยความจำจริงๆ เนื่องจากไม่ใช่ตัวเลขที่ระบุตำแหน่งหน่วยความจำ แต่แล้วการอ้างอิง คือ อะไร?
การอ้างอิงใน PHP คืออะไร ?
ใน PHP การอ้างอิงคือ "นามแฝง" ที่อนุญาตให้สองตัวแปรที่แตกต่างกันอ่านและเขียนค่าเดียว กล่าวอีกนัยหนึ่ง สิ่งเหล่านี้เป็นกลไกที่อนุญาตให้เข้าถึงค่าเดียวกันจากตัวแปรที่มีชื่อต่างกัน เพื่อให้ทำงานราวกับว่าเป็นตัวแปรเดียวกัน โปรดทราบว่าใน PHP ชื่อตัวแปรและเนื้อหาของตัวแปรเป็นสองสิ่งที่แตกต่างกันโดยสิ้นเชิง ซึ่งเชื่อมโยงในสิ่งที่เรียกว่า "ตารางสัญลักษณ์" ดังนั้น เมื่อเราสร้างการอ้างอิง มันจะเพิ่มนามแฝงสำหรับตัวแปรนั้นในตารางสัญลักษณ์ สมมติว่าเรามีรหัสต่อไปนี้:
$a = new Foo(); เมื่อดำเนินการคำสั่งข้างต้น ตัวแปร $a จะถูกสร้างขึ้นในหน่วยความจำ วัตถุประเภท Foo จะถูกสร้างขึ้นในหน่วยความจำ และรายการจะถูกเพิ่มลงในตารางสัญลักษณ์ซึ่งบ่งชี้ว่าตัวแปร $a “การอ้างอิง” (หรือเกี่ยวข้องกับ หรือชี้ไปที่หรือสิ่งที่คุณต้องการเรียก) วัตถุ Foo แต่ไม่ใช่ ตัวชี้ ไปยังวัตถุนั้นโดยส่วนตัว ตามแนวคิดแล้ว เรามีบางอย่างเช่นภาพประกอบนี้:
แบบทดสอบป๊อป: จะเกิดอะไรขึ้นถ้าเราดำเนินการนี้
$b = $a; ไม่ใช่ว่า $b กลายเป็นข้อมูลอ้างอิงของ $a ; เราไม่สามารถพูดได้ว่า $b เป็นสำเนาของ $a สิ่งที่เกิดขึ้นจริงคือเราได้สร้างตัวแปร $b ใหม่ในหน่วยความจำแล้วเพิ่มรายการใหม่ในตารางสัญลักษณ์ที่ระบุว่าตัวแปร $b ยังอ้างอิงวัตถุ Foo เดียวกันกับที่ $a ทำ ดังนั้น ทางสายตา เรามีบางสิ่งที่คล้ายกับที่แสดงในภาพประกอบนี้:
ตอนนี้ถ้าเราดำเนินการ:
$c = &$a; เราจะสร้างตัวแปรตัวที่สาม $c ในหน่วยความจำ แต่ ไม่ใช่ รายการใหม่ในตารางสัญลักษณ์สำหรับ $c ในตารางสัญลักษณ์ จะมีการบันทึกว่า $c เป็นนามแฝงสำหรับ $a ดังนั้นจะมีการทำงานเหมือนกัน แต่ $c ไม่ใช่ตัวชี้ไปยัง $a แตกต่างจาก C ซึ่งสร้างสิ่งที่เรียกว่า pointers to pointers เพื่อให้เห็นภาพ เรามีบางสิ่งที่คล้ายกับที่แสดงในภาพประกอบนี้:

ทันทีที่เราต้องการแก้ไขค่าของตัวแปรสามตัวเหล่านี้ (เช่น เขียนค่าใหม่) PHP จะต้องสร้างโครงสร้าง z_val ใหม่ในหน่วยความจำเพื่อแยกเนื้อหาของตัวแปร $b และคู่ $a / $c เพื่อให้สามารถแก้ไขได้โดยอิสระโดยไม่กระทบต่อมูลค่าของอีกฝ่าย ดังนั้น หากเราเพิ่มบรรทัดต่อไปนี้ในสคริปต์ก่อนหน้า:
$b = new Bar();ในความทรงจำ เราจะมีสถานการณ์ดังแสดงในภาพประกอบต่อไปนี้:
ตอนนี้ มาลองพิจารณาตัวอย่างที่สมบูรณ์กว่านี้:
<?php class myClass { public $var; function __construct() { $this->var = 1; } function inc() { return ++$this->var; } } $a = new myClass(); // $a "references" a Foo object $b = $a; //b also references the same Foo object as a //($a) == ($b) == <id> of Foo object, but a and b are different entries in symbols table echo "$a = ";var_dump($a); echo "$b = ";var_dump($b); $c = &$a; //$c is an alias of $a //($a, $c) == <id> of Foo object, c is an alias of a in the symbols table echo "$c = ";var_dump($c); $a = NULL; //The entry in the symbols table which links "$a" with Foo object is removed //Since that entry was removed, $c is not related to Foo anymore //Anyway, Foo still exists in memory and it is still linked by $b echo "$a = ";var_dump($a); echo "$b = ";var_dump($b); echo "$c = ";var_dump($c); echo "$b->var: ".$b->inc(); echo "$b->var: ".$b->inc(); $b = NULL; //The entry in the symbols table which links "$b" with the Foo object is removed //There are no more entries in the symbols table linked to Foo, //So, Foo is not referenced anymore and can be deleted by the garbage collector echo "$b = ";var_dump($b);ผลลัพธ์ที่ได้จากการใช้งานสคริปต์ด้านบนคือ:
$a = object(myClass)#1 (1) { ["var"]=> int(1) } $b = object(myClass)#1 (1) { ["var"]=> int(1) } $c = object(myClass)#1 (1) { ["var"]=> int(1) } $a = NULL $b = object(myClass)#1 (1) { ["var"]=> int(1) } $c = NULL $b->var: 2 $b->var: 3 $b = NULLPHP Garbage Collection
สุดท้าย เรามาดูกันว่าการรวบรวมขยะของ PHP ทำงานอย่างไร เนื่องจากมันเปิดตัวในเวอร์ชัน 5.3 วัตถุหรือตัวแปรในหน่วยความจำ PHP จะถูกลบออกโดยตัวรวบรวมขยะ PHP เมื่อไม่มีการอ้างอิงถึงวัตถุนั้นในตารางสัญลักษณ์ นั่นคือ PHP รักษาตัวนับอ้างอิงของวัตถุตั้งแต่เวลาที่สร้างขึ้นเพื่อให้ในระหว่างการดำเนินการของสคริปต์ PHP ตัวนับจะเพิ่มขึ้นและลดลงที่ตัวนับอ้างอิงตามตัวแปรที่ "ชี้" ไปที่มัน เมื่อจำนวนการอ้างอิงถึง 0 (กล่าวคือ ไม่มีการอ้างถึงวัตถุนั้นและดังนั้นจึงไม่มีการใช้วัตถุนั้น) PHP จะทำเครื่องหมายวัตถุนั้นเป็นแบบถอดได้ เพื่อที่ในครั้งต่อไปของตัวรวบรวมขยะ PHP วัตถุนั้นจะถูกลบออกจากหน่วยความจำ ทำให้มีพื้นที่ว่างสำหรับนำกลับมาใช้ใหม่ หากคุณต้องการรายละเอียดเชิงลึกเพิ่มเติมเกี่ยวกับวิธีการทำงานของการรวบรวมขยะของ PHP โปรดอ่านเอกสารนี้
ปิดความคิด
ฉันหวังว่าฉันได้ชี้แจงเล็กน้อยว่า PHP จัดการกับวัตถุและตัวแปรในหน่วยความจำอย่างไร และมัน "เลือก" วัตถุอย่างไรที่ควรลบโดยตัวรวบรวมขยะ PHP
ตอนนี้คุณเข้าใจวิธีที่ PHP จัดการตัวแปรและอ็อบเจ็กต์ในหน่วยความจำภายในแล้ว คว้าแล็ปท็อปของคุณแล้วเริ่มทดลองโค้ดเพื่อพิสูจน์สิ่งที่คุณได้เรียนรู้ ลองเล่นกับตัวแปรและข้อมูลอ้างอิง นอกจากนี้ ให้ทดลองว่าการเปลี่ยนแปลงค่าของตัวแปรอาจส่งผลต่อค่าของตัวแปรอื่นที่อ้างอิงได้อย่างไร นี่คือคำถามสำหรับคุณ: ค่าของ $a และ $b จะเป็นอย่างไรหลังจากรันโค้ดด้านล่าง
$a = '1'; $b = &$a; $b = "2$b";หากคุณสนใจที่จะอ่านเพิ่มเติมเกี่ยวกับคุณลักษณะด้านประสิทธิภาพของ PHP โปรดดูโพสต์นี้โดยเพื่อน Toptaler Vilson Duka
