من هو إلفيس وما علاقته بـ PHP؟
\n\nإذا كنت قد كتبت أي كود PHP من قبل، فمن المحتمل أنك رأيت تركيبات غريبة في كود الآخرين: $name ?: 'ضيف' أو $name ?? 'ضيف'. للوهلة الأولى، يبدوان متطابقين. لكن في الواقع، وراء هذين العاملين تختبئ آليات مختلفة تمامًا يمكنها إما إنقاذ كودك أو التسبب في مشاكل.
على Stack Overflow، جمع سؤال "عامل PHP الثلاثي المختصر ("Elvis") مقابل العامل الفارغ" عشرات الآلاف من المشاهدات. وهذا ليس من قبيل الصدفة. يختلط الأمر على المطورين، ويخطئون، ثم يقضون وقتًا طويلاً في البحث عن الأخطاء. دعونا نفهم الأمر مرة واحدة وإلى الأبد، ونتوقف عن التخمين.
\n\nفي هذه المقالة، لن نقوم فقط بسرد الاختلافات. سننظر تحت غطاء PHP، ونرى حالات حقيقية من بيئات الإنتاج، ونفهم متى نستخدم أي عامل. هيا بنا!
\n\nنبذة تعريفية سريعة: ما هذا بحق الجحيم؟
\n\nالعامل الثلاثي (التقليدي)
\nفي البداية، دعنا نتذكر الأساسيات. العامل الثلاثي هو صيغة مختصرة لـ if-else:
\n\n$age = 20;\n$status = ($age >= 18) ? 'بالغ' : 'طفل';\n// $status = 'بالغ'\n\nالأمر بسيط: إذا كان الشرط صحيحًا، نأخذ القيمة الأولى، وإلا نأخذ الثانية.
\n\nالعامل الثلاثي المختصر (المعروف أيضًا باسم عامل Elvis) — ?:
\nهذا اختصار للحالة التي تتحقق فيها من "صحة" متغير وتريد استخدام قيمته نفسها:
\n\n$name = 'أليكسي';\n$greeting = $name ?: 'ضيف';\n// $greeting = 'أليكسي'\n\n$name = '';\n$greeting = $name ?: 'ضيف';\n// $greeting = 'ضيف'\n\nيعمل كالتالي: إذا تم تحويل $name إلى true، نأخذ $name. وإلا، نأخذ "ضيف".
العامل الفارغ — ??
\nظهر في PHP 7.0 وأصبح على الفور المفضل لدى المطورين:
\n\n$name = 'أليكسي';\n$greeting = $name ?? 'ضيف';\n// $greeting = 'أليكسي'\n\n$name = null;\n$greeting = $name ?? 'ضيف';\n// $greeting = 'ضيف'\n\nالفرق عن إلفيس: التحقق يكون فقط من null، وليس من "الخطأ" بشكل عام.
\n\nالفرق الرئيسي: ما الذي يعتبر "فارغًا"؟
\n\nهنا يبدأ الجزء المثير للاهتمام. دعونا نلقي نظرة على جدول مقارنة لقيم مختلفة لـ $value:
$value = false;\necho $value ?: 'افتراضي'; // 'افتراضي' (false هي "خطأ")\necho $value ?? 'افتراضي'; // false (false ليست null)\n\n$value = 0;\necho $value ?: 'افتراضي'; // 'افتراضي' (0 هي "خطأ")\necho $value ?? 'افتراضي'; // 0 (0 ليست null)\n\n$value = '';\necho $value ?: 'افتراضي'; // 'افتراضي' (سلسلة فارغة هي "خطأ")\necho $value ?? 'افتراضي'; // '' (سلسلة فارغة ليست null)\n\n$value = [];\necho $value ?: 'افتراضي'; // 'افتراضي' (مصفوفة فارغة هي "خطأ")\necho $value ?? 'افتراضي'; // [] (مصفوفة فارغة ليست null)\n\n$value = '0';\necho $value ?: 'افتراضي'; // 'افتراضي' (السلسلة "0" هي "خطأ"!)\necho $value ?? 'افتراضي'; // '0' (السلسلة "0" ليست null)\n\nهل ترى الفرق؟ إلفيس يعمل كتحقق من "الصحة" (truthy/falsy)، بينما العامل الفارغ هو تحقق صارم من الوجود والاختلاف عن null.
\n\nتحت الغطاء: كيف يعمل هذا على مستوى المحرك
\n\nدعونا نلقي نظرة على شفرة مصدر PHP (تقريبًا). إذا كنت قد قمت بتجميع PHP من المصدر من قبل، فأنت تعلم أن كلا العاملين يتم معالجتهما في مرحلة التحليل (parsing).
\n\nالعامل الثلاثي المختصر (?):
\nفي الواقع، هذا سكر نحوي (syntactic sugar). $a ?: $b يتحول إلى $a ? $a : $b. لكن هناك فارق بسيط: PHP لا تحسب $a مرتين. إنها تحفظ النتيجة في متغير مؤقت. هذا مهم للدوال ذات التأثيرات الجانبية:
function getData() {\n echo "تم استدعاء الدالة!\\n";\n return rand(0, 1) ? 'data' : '';\n}\n\n// إلفيس سيستدعي الدالة مرة واحدة\n$result = getData() ?: 'افتراضي';\n// "تم استدعاء الدالة!" — مرة واحدة\n\nإذا كانت PHP ستحسب $a مرتين،