مقدمة عن الكائنات والمراجع في ذاكرة 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 ، الذي ينشئ شيئًا يسمى مؤشرات إلى المؤشرات . للتصور ، لدينا شيء مشابه لما يظهر في هذا الرسم التوضيحي:

بمجرد أن نرغب في تعديل قيمة أي من هذه المتغيرات الثلاثة (على سبيل المثال ، اكتب قيمة جديدة) ، سيتعين على 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 = NULL
جمع القمامة PHP
أخيرًا ، لنرى كيف تعمل 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.