متى تستخدم self ومتى تستخدم $this؟ شرح نهائي
\n\nإذا كنت قد كتبت كود PHP بأسلوب البرمجة كائنية التوجّه (OOP)، فبالتأكيد واجهت السؤال: "أيهما أختار — self أم $this؟". هذا السؤال شائع جداً لدرجة أنه حصل على عشرات الآلاف من المشاهدات ومئات التعليقات على Stack Overflow. وهذا ليس من قبيل الصدفة: الفرق بينهما هو أحد تلك "التفاصيل الصغيرة" التي يمكن أن تجعل كودك يعمل بشكل غير واضح، أو أنيق وسهل الفهم.
دعنا نتفق فوراً: هذان المفهومان ليسا قابلين للتبديل. لهما فلسفة مختلفة، والأهم من ذلك، سلوك مختلف عند التعامل مع الوراثة (Inheritance). إذا استخدمت $this في مكان يحتاج self، أو العكس — فأنت تخاطر بحدوث أخطاء منطقية يصعب اكتشافها.
في هذا المقال، سنشرح كل شيء بالتفصيل: من الأساسيات إلى السيناريوهات المتقدمة. هيا بنا!
\n\n\n\n
إجابة سريعة (للمستعجلين)
\n\nإذا كنت تريد تذكر قاعدة واحدة فقط، فتذكر هذا:
\n\n- \n
$this->— للوصول إلى خصائص وطرق الكائن (المثيل). يعمل فقط داخل السياق غير الثابت (non-static context). \n self::— للوصول إلى الخصائص والطرق الثابتة (static) للكلاس. يعمل في كل من السياق الثابت وغير الثابت. \n static::— "الربط الثابت المتأخر" (Late Static Binding). يُستخدم عندما تريد أن يقوم الكلاس الفرعي بتجاوز سلوك الكلاس الأب. \n
ولكن، كما هو الحال دائماً، الشيطان يكمن في التفاصيل. دعنا نتعمق أكثر.
\n\nما هو $this؟
\n\n$this هو متغير وهمي (pseudo-variable) يشير إلى الكائن الحالي. وهو متاح فقط داخل طرق الكلاس (غير الثابتة) ويشير إلى المثيل الذي تتعامل معه.
<?php\n\nclass User {\n public string $name;\n\n public function setName(string $name): void {\n $this->name = $name; // الوصول إلى خاصية الكائن الحالي\n }\n\n public function getName(): string {\n return $this->name;\n }\n}\n\n$user = new User();\n$user->setName('سارة');\necho $user->getName(); // سارة\n\nالأمر بسيط: $this->name تعني "خذ خاصية name من الكائن الذي استدعى هذه الطريقة".
ما هو self؟
\n\nself هو مرجع إلى الكلاس الحالي، وليس إلى الكائن. يُستخدم للوصول إلى الأعضاء الثابتة في الكلاس (الخصائص والطرق المعلنة بكلمة static).
<?php\n\nclass Config {\n public static string $appName = 'PythonLib';\n\n public static function getAppName(): string {\n return self::$appName; // الوصول إلى الخاصية الثابتة للكلاس\n }\n}\n\necho Config::getAppName(); // PythonLib\n\nلاحظ: self يشير دائماً إلى الكلاس الذي كُتب فيه. حتى لو أنشأت كلاساً فرعياً، فإن self في الكلاس الأب سيستمر في الإشارة إلى الأب. هذا هو الفرق الأهم بينه وبين static.
الفرق الرئيسي: self vs $this عند الوراثة
\n\nهنا يبدأ الجزء الممتع. تخيل أن لديك كلاساً أساسياً Animal وكلاساً فرعياً Dog.
<?php\n\nclass Animal {\n public static function whoAmI(): string {\n return 'أنا حيوان';\n }\n\n public function say(): string {\n // نستخدم self — وهو مرتبط بكلاس Animal\n return self::whoAmI();\n }\n}\n\nclass Dog extends Animal {\n public static function whoAmI(): string {\n return 'أنا كلب';\n }\n}\n\n$dog = new Dog();\necho $dog->say(); // أنا حيوان