التكرار الأول والأخير في foreach: مطبات وحلول PHP

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

لماذا يثير سؤال "التكرار الأول والأخير في foreach" ضجة في Stack Overflow؟



إذا كنت قد كتبت كودًا بلغة PHP وحاولت إضافة كلاس CSS إلى العنصر الأول في القائمة أو إدراج فاصل بعد كل عنصر باستثناء الأخير، فأنت بالتأكيد واجهت هذه المشكلة. في Stack Overflow، حصد هذا السؤال أكثر من 150,000 مشاهدة ومئات التعليقات. لماذا؟ لأن foreach حلقة قوية ولكنها "عمياء": فهي لا تعرف في أي دورة هي.



في هذه المقالة، سنستعرض 4 طرق عملية في PHP 8.x، من البسيطة إلى الاحترافية. ستتعلم كيفية تجنب الحلول "القذرة" وكتابة كود لا تخجل من عرضه في مراجعة الكود.





المشكلة: لماذا لا تعرف foreach رقمها؟



على عكس for، حيث لديك عداد $i، تعمل foreach مع المؤشر الداخلي للمصفوفة. إنها مثالية للتكرار البسيط، ولكن عندما تحتاج إلى تنفيذ إجراء "لأول عنصر فقط" أو "لآخر عنصر فقط"، تبدأ المتاعب.



مثال على مهمة نموذجية:

// عرض قائمة المنتجات مفصولة بفاصلة، ولكن بدون فاصلة بعد الأخير$items = ['حليب', 'خبز', 'بيض', 'جبن'];

foreach ($items as $item) { echo $item . ', '; // أوه، الفاصلة الأخيرة زائدة!}


النتيجة: حليب, خبز, بيض, جبن, — هذا غير جميل. دعنا نصلحها.



الطريقة 1: العداد + count() — الكلاسيكية



الطريقة الأكثر وضوحًا هي استخدام متغير عداد ومقارنته بإجمالي عدد العناصر.



$items = ['حليب', 'خبز', 'بيض', 'جبن'];$total = count($items);$i = 1;

foreach ($items as $item) { if ($i === 1) { echo "<strong>الأول: $item</strong><br>"; } elseif ($i === $total) { echo "<em>الأخير: $item</em><br>"; } else { echo "$item<br>"; } $i++;}


المزايا:

  • البساطة وسهولة القراءة.
  • تعمل مع أي مصفوفات، بما في ذلك المصفوفات الترابطية.


العيوب:

  • تحتاج إلى تذكر استخدام count() وتهيئة العداد.
  • إذا كانت المصفوفة فارغة، $total = 0، ولن يحدث التكرار الأول أبدًا — يجب التحقق من ذلك.
  • لا تناسب كائنات Iterator (مثل المولدات).


الطريقة 2: العلامات و reset() / end() — أناقة بدون عداد



يمكنك عدم حساب التكرارات، بل ببساطة تذكر العنصر الأول والأخير من المصفوفة قبل بدء الحلقة.



$items = ['حليب', 'خبز', 'بيض', 'جبن'];

$first = reset($items); // 'حليب'$last = end($items); // 'جبن'reset($items); // إعادة المؤشر إلى البداية!

foreach ($items as $key => $item) { if ($item === $first) { echo "الأول: $item"; } elseif ($item === $last) { echo "الأخير: $item"; } else { echo "$item"; }}


مهم! الدالتان reset() و end() تغيران المؤشر الداخلي للمصفوفة. بعد end()، يجب استدعاء reset()، وإلا ستبدأ foreach من غير البداية.



المزايا:

  • لا حاجة لعداد.
  • تعمل مع المصفوفات الترابطية.


العيوب:

  • خطر: إذا كانت المصفوفة تحتوي على قيم مكررة (مثل "جبن" مرتين)، فسيتم تحديد العنصر الأخير بشكل غير صحيح.
  • لا تناسب كائنات Iterator.
  • تتطلب إعادة تعيين المؤشر يدويًا.


الطريقة 3: array_keys() — للمصفوفات الترابطية والكائنات



إذا كنت بحاجة إلى العمل مع المفاتيح (وليس فقط القيم) أو مع كائنات Iterator، يمكنك الحصول على قائمة بجميع المفاتيح والتحقق من الفهرس.



$items = ['a' => 'حليب', 'b' => 'خبز', 'c' => 'بيض', 'd' => 'جبن'];$keys = array_keys($items);$lastKey = end($keys);

foreach ($items as $key => $item) { if ($key === $keys[0]) { echo "الأول: $item"; } elseif ($key === $lastKey) { echo "الأخير: $item"; } else { echo "$item"; }}


المزايا:

  • تعمل مع المفاتيح الترابطية.
  • مناسبة لكائنات Iterator (إذا كانت تدعم array_keys).


العيوب:

  • تستهلك ذاكرة إضافية لتخزين المفاتيح.
  • لا تعمل مع المصفوفات الكبيرة جدًا بكفاءة عالية.

المدونات

توصيات الكتب