مقدمة: حرف صغير يغير كل شيء
\n\nتخيل أنك تكتب إطار عمل PHP رائع أو مجرد مكتبة لمشروعك. كل شيء يعمل بشكل مثالي، ولكن بعد شهر تلاحظ أن الفئات الفرعية تتصرف بطريقة غير متوقعة. تقوم بإنشاء كائن، وفجأة يعيد لك نسخة من الفئة الأم! هل يبدو هذا مألوفاً؟ مرحباً بك في نادي من واجهوا مشكلة new self vs. new static.
\n\nهذا السؤال على Stack Overflow حصد آلاف المشاهدات، وليس من دون سبب. الفرق بين self و static في PHP ليس مجرد سكر نحوي، بل هو آلية أساسية يمكنها إما إنقاذ مشروعك أو تحويله إلى كابوس صيانة. في عام 2025، مع استمرار تطور PHP، أصبح فهم الربط الثابت المتأخر (Late Static Binding) مهارة إلزامية لأي مطور يحترم نفسه.
في هذه المقالة، لن نعيد سرد الوثائق فقط. سنحلل حالات واقعية، ونعرض الأنماط الخاطئة، ونقدم أفضل الممارسات الواضحة التي يمكنك تطبيقها اليوم. هيا بنا!
\n\nالجزء الرئيسي: self vs. static — معركة السياق
\n\n1. self — المحافظ في زمن الترجمة
\n\nالكلمة المفتاحية self في PHP تشير دائماً إلى الفئة التي كُتبت فيها. فكر فيها كصديق قديم لا يتغير أبداً. عندما تكتب new self() في الفئة الأم، فإن هذا الكود سينشئ دائماً كائن من هذه الفئة الأم بالضبط — حتى لو تم استدعاؤه من فئة فرعية.
<?php\nclass Animal {\n public static function create() {\n return new self(); // دائماً Animal\n }\n}\n\nclass Dog extends Animal {\n // يرث create()\n}\n\n$dog = Dog::create();\necho get_class($dog); // سيطبع: Animal\n?>\n\nأرأيت؟ لقد استدعينا الطريقة من الفئة Dog، لكننا حصلنا على Animal. هذا غالباً ما يكون مفاجأة للمبتدئين. ما السر؟ السر هو أن self يتم حله في مرحلة الترجمة. PHP «تغلق» المرجع إلى الفئة التي أُعلنت فيها الطريقة، ولا يمكن لأي سحر وراثة تغيير ذلك.
2. static — الرابط المتأخر الثوري
\n\nأما static فهو العكس تماماً. إنه يعمل في لحظة استدعاء الطريقة ويحدد أي فئة قامت باستدعائها. هذا هو الربط الثابت المتأخر (Late Static Binding)، الذي ظهر في PHP 5.3.0.
<?php\nclass Animal {\n public static function create() {\n return new static(); // ينشئ نسخة من الفئة التي استدعت الطريقة\n }\n}\n\nclass Dog extends Animal {\n // يرث create()\n}\n\n$dog = Dog::create();\necho get_class($dog); // سيطبع: Dog\n?>\n\nيا له من تغيير! الآن Dog::create() يعيد كلباً وليس حيواناً مجرداً. static ينظر إلى من استدعى الطريقة، وينشئ كائن من تلك الفئة بالضبط. هذا يعطي مرونة لا تصدق عند بناء تسلسلات هرمية للفئات.
3. متى نستخدم self ومتى نستخدم static؟
\n\nالقاعدة الذهبية: استخدم self عندما تحتاج إلى ربط ثابت بالفئة الحالية، واستخدم static عندما تريد أن تتمكن الفئات الفرعية من تجاوز السلوك.
إليك بعض السيناريوهات المحددة:
\n\nالسيناريو أ: طرق المصنع (استخدم static)
\nمثال كلاسيكي هو نمط Factory Method. تريد أن تقوم كل فئة فرعية بإنشاء نفسها بنفسها.
\n\n<?php\nabstract class Vehicle {\n abstract public function getType(): string;\n\n public static function create(): static {\n return new static();\n }\n}\n\nclass Car extends Vehicle {\n public function getType(): string {\n return 'سيارة';\n }\n}\n\nclass Bike extends Vehicle {\n public function getType(): string {\n return 'دراجة';\n }\n}