أول وآخر عنصر في حلقة foreach: الصداع الدائم لمطور PHP
\n\nتخيل موقفًا: أنت تعرض قائمة منتجات في متجر إلكتروني. يجب أن يحمل المنتج الأول علامة "الأكثر مبيعًا"، والمنتج الأخير علامة "جديد". أو لنفترض أنك تقوم بإنشاء خلاصة XML حيث يجب تغليف العناصر بعلامات حاوية، ولكن فقط للعنصر الأول والأخير. كيف تفعل ذلك في PHP؟ قد تبدو المهمة بسيطة، لكنها حصدت آلاف المشاهدات وعشرات الحلول على Stack Overflow.
\n\nلماذا تسبب هذه المهمة البسيطة ظاهريًا كل هذا الجدل؟ السبب هو أن foreach في PHP هو مكرر (iterator) لا يوفر طرقًا مدمجة لتحديد رقم التكرار. على عكس حلقة for حيث لدينا عداد $i، في foreach نتعامل فقط مع المفتاح والقيمة. وهنا يبدأ السحر: البعض يستخدم العدادات، والبعض يستخدم دوال reset() و end()، والبعض الآخر يستخدم حيلًا ذكية مع مؤشرات المصفوفة.
في هذه المقالة، سنستعرض ثلاث طرق رئيسية لتحديد أول وآخر تكرار في foreach، ونقارن بين أدائها، وسهولة قراءتها، وموثوقيتها. ستتعرف على الطريقة الأنسب لمهمتك وكيفية تجنب الأخطاء الشائعة. هيا بنا!
الطريقة الأولى: العداد التقليدي (الأكثر وضوحًا)
\n\nالطريقة الأكثر بداهة هي استخدام متغير عداد ومقارنته بإجمالي عدد عناصر المصفوفة. تُعرف هذه الطريقة أحيانًا بالطريقة "التقليدية"، لكنها تعمل بدون أخطاء.
\n\n<?php\n$items = ['تفاح', 'موز', 'كرز', 'شمام'];\n$total = count($items);\n$counter = 0;\n\nforeach ($items as $item) {\n $counter++;\n if ($counter === 1) {\n echo "<strong>الأول: $item</strong><br>";\n } elseif ($counter === $total) {\n echo "<em>الأخير: $item</em><br>";\n } else {\n echo "$item<br>";\n }\n}\n?>\n\nالمزايا:
\n- \n
- منطق واضح للغاية — أي مبتدئ سيفهم الكود من النظرة الأولى. \n
- لا يعتمد على نوع مفاتيح المصفوفة (يعمل مع المصفوفات الترابطية والرقمية). \n
- سهل التعديل: تريد التحقق من التكرار الثاني أو قبل الأخير؟ فقط غيّر الشرط. \n
العيوب:
\n- \n
- يتطلب استدعاء
count()للمصفوفة بأكملها — وهذا حمل صغير، لكنه قد يكون ملحوظًا في المصفوفات الكبيرة جدًا (ملايين العناصر). \n - يجب ألا تنسى تهيئة العداد قبل الحلقة. \n
- إذا كانت المصفوفة فارغة، سيكون
$totalيساوي 0، ولن يعمل الشرط$counter === $totalأبدًا (وهو منطقي، لكن المبتدئين ينسون ذلك). \n
الطريقة الثانية: استخدام reset() و end() الذكية (لعشاق الإيجاز)
\n\nفي PHP، هناك دالة reset() التي تُرجع العنصر الأول من المصفوفة، ودالة end() التي تُرجع العنصر الأخير. الحيلة هي أننا يمكننا مقارنة العنصر الحالي بهذه القيم داخل الحلقة.
<?php\n$items = ['تفاح', 'موز', 'كرز', 'شمام'];\n$first = reset($items);\n$last = end($items);\n\nforeach ($items as $item) {\n if ($item === $first) {\n echo "<strong>الأول: $item</strong><br>";\n } elseif ($item === $last) {\n echo "<em>الأخير: $item</em><br>";\n } else {\n echo "$item<br>";\n }\n}\n?>\n\nالمزايا:
\n- \n
- الكود يبدو مضغوطًا و"أنيقًا" للغاية. \n
- لا حاجة لاستخدام عداد أو دالة
count(). \n
العيوب:
\n- \n
- المشكلة الرئيسية: إذا كانت المصفوفة تحتوي على قيم مكررة، فستفشل هذه الطريقة. تخيل أن العنصر الأول والثالث متطابقان. سيعتقد الكود أن العنصر الثالث هو أيضًا الأول. \n
reset()