Menu

לולאת foreach ב-PHP: מפתח וערך, אינדקס והפניה

foreach ($array as $value) עוברת על כל איבר במערך, ו-foreach ($array as $key => $value) נותנת גם את המפתח. כולל קבלת האינדקס, שינוי ערכים דרך הפניה ומלכודת ה-unset(), break ו-continue, מערכים מקוננים, list() בתוך foreach ובניית HTML.

בדף הזה יש עורכים שאפשר להריץ - לערוך, להריץ ולראות את הפלט מיד.

foreach ($array as $value) מריצה את הבלוק פעם אחת לכל איבר, כש-$value מכיל את האיבר הנוכחי. כדי לקבל גם את המפתח, כתבו foreach ($array as $key => $value).

foreach עובדת על כל מערך, יהיו המפתחות שלו אשר יהיו, ואף פעם לא מנהלים מונה או בודקים אורך. זו הלולאה שתכתבו הכי הרבה ב-PHP.

מעבר על מפתחות וערכים

ב-$key => $value, השמות לבחירתכם: $name => $age, $id => $user, $k => $v. ברשימה, המפתחות הם המיקומים 0, 1, 2. במערך אסוציאטיבי, הם מפתחות המחרוזת שהגדרתם.

הלולאה האחרונה מראה פרט שמפתיע אנשים: מפתח מחרוזת שנראה כמו מספר שלם, כמו "1", נשמר כמספר השלם 1. "01" אינו מספר שלם בצורה קנונית, ולכן הוא נשאר מחרוזת.

קבלת האינדקס ב-foreach

ברשימה, המפתח הוא האינדקס, ולכן foreach ($items as $i => $item) זה כל מה שצריך. במערך אסוציאטיבי אין מיקום מספרי, אז החזיקו מונה. כדי לטפל אחרת באיבר הראשון או האחרון, השוו את המפתח ל-array_key_first() או ל-array_key_last().

הלולאה האחרונה מדפיסה פסיק בין שמות אבל לא אחרי האחרון. לעבודה המדויקת הזו implode(', ', array_keys($scores)) קצרה יותר; הבדיקה של array_key_last() נועדה למקרים שבהם הסבב האחרון צריך לוגיקה שונה, ולא רק מפריד שונה.

שינוי ערכי מערך ב-foreach (דרך הפניה)

$value הוא עותק. הצבה אליו לא משנה שום דבר במערך. כדי לשנות את המערך, עברו בלולאה דרך הפניה עם &$value, או כתבו בחזרה דרך המפתח.

שתי הדרכים עובדות. בגרסת המפתח לא נשאר מצב נסתר אחרי הלולאה, ולכן צוותים רבים מעדיפים אותה. כדי לבנות מערך חדש במקום לשנות קיים, array_map() היא אפשרות נוספת.

שאלה קשורה: מה קורה אם מוסיפים איברים תוך כדי הלולאה? foreach רגילה עוברת על המערך כפי שהיה כשהלולאה התחילה, ולכן $prices[] = ... בתוכה לא יוצר סבבים נוספים. לולאה דרך הפניה עוברת על המערך החי ואכן מבקרת באיברים החדשים.

מלכודת ה-unset() ב-foreach עם הפניה

אחרי foreach ($arr as &$v), המשתנה $v הוא עדיין הפניה לאיבר האחרון של המערך. אם בהמשך משתמשים שוב בשם $v בלולאה רגילה, כל סבב כותב לתוך האיבר האחרון הזה. הריצו את זה והסתכלו על הפריט האחרון:

הלולאה השנייה מציבה ב-$letters[2] את A, אחר כך את B, ואז את הערך של האיבר האחרון עצמו, ובסבב האחרון המקום הזה כבר מחזיק B. התיקון הוא שורה אחת: שימו unset($v); מיד אחרי כל foreach עם הפניה.

break ו-continue ב-foreach

break יוצא מהלולאה, continue מדלג לאיבר הבא. דפוס נפוץ הוא חיפוש: עוברים בלולאה עד שמוצאים את מה שצריך, ואז break כדי ששאר המערך לא ייבדק.

בלולאות מקוננות, break 2 יוצא מהלולאה הפנימית ומזו שסביבה, ו-continue 2 קופץ לסבב הבא של הלולאה החיצונית.

מערכים מקוננים ו-foreach עם list()

שורות נתונים הן מערכים בתוך מערך. עברו על השורות, ואז על כל שורה, או שלפו את השדות ישירות בשורת ה-foreach עם פירוק מערך: [$a, $b] לרשימות, ['key' => $var] לשורות אסוציאטיביות. list($a, $b) הוא הכתיב הישן של [$a, $b].

בעמוד פירוק המערכים יש עוד על התחביר [...] =, כולל דילוג על איברים ותבניות מקוננות.

בניית רשימה או טבלת HTML עם foreach

בתבנית, צורת הנקודתיים foreach (...): עם endforeach; שומרת על הלולאה קריאה בין התגיות. הבלוק הזה בונה טבלה, וכותרות העמודות הן קישורים: לחצו על אחת בלשונית Page ואותו סקריפט ירוץ שוב עם $_GET['sort'] מוגדר, כך שהשורות יחזרו בסדר חדש.

שני הרגלים ששווה להעתיק מהבלוק הזה: הערך sort מכתובת ה-URL נבדק מול רשימת עמודות מותרות לפני שמשתמשים בו, וכל ערך שמודפס לתוך HTML ויכול להכיל טקסט של משתמש עובר דרך htmlspecialchars().

foreach על null, על מערך ריק או על אובייקט

מערך ריק זה בסדר: הגוף לא רץ אף פעם. null, מחרוזת או מספר לא: PHP מדפיסה אזהרה ומדלגת על הלולאה. עבור $tags = null; foreach ($tags as $tag) היא מדפיסה:

Warning: foreach() argument must be of type array|object, null given in /var/www/html/index.php on line 4

זה קורה הכי הרבה עם נתונים שלפעמים חסרים, כמו שדה אופציונלי ב-JSON מפוענח. עברו למערך ריק עם ??:

foreach ($data['tags'] ?? [] as $tag) {
    echo $tag;
}

ה-object בהודעה הזו אמיתי: foreach על אובייקט עוברת על המאפיינים שלו שגלויים מהמקום שבו הלולאה רצה (מחוץ למחלקה, הציבוריים), כששם המאפיין הוא המפתח. מחלקות שמממשות Iterator או IteratorAggregate, וגנרטורים, מחליטים בעצמם מה foreach רואה.

foreach מול for מול array_map

השתמשו במתי
foreachאתם רוצים כל איבר, עם המפתח שלו או בלעדיו. עובדת על כל מערך, רשימה או אסוציאטיבי.
forאתם סופרים (1 עד 100, כל איבר שני) או צריכים שכנים לפי אינדקס ($a[$i - 1]). ראו את לולאת for.
array_map()אתם בונים מערך חדש על ידי שינוי של כל איבר, לעיתים קרובות בשורה אחת עם fn.
array_filter()אתם שומרים רק את האיברים שעוברים בדיקה.

דרך מהירה להחליט: אם גוף הלולאה רק מחשב ערך חדש לכל איבר, array_map(fn($x) => $x * 2, $a) אומרת את זה בשורה אחת. אם יש לו תופעות לוואי (הדפסה, שמירה, ספירה של כמה דברים בבת אחת) או שהוא צריך break, כתבו את ה-foreach.

שאלות נפוצות

איך מקבלים את המפתח והערך בלולאת foreach ב-PHP?

השתמשו בצורה עם =>: foreach ($array as $key => $value) { echo "$key: $value"; }. ברשימה רגילה המפתח הוא האינדקס (0, 1, 2); במערך אסוציאטיבי הוא מפתח המחרוזת, כמו 'name'.

איך מקבלים את האינדקס בלולאת foreach ב-PHP?

ברשימה, המפתח כבר הוא האינדקס: foreach ($items as $i => $item). במערך אסוציאטיבי, החזיקו מונה משלכם: הציבו $i = 0; לפני הלולאה ו-$i++ בסוף כל סבב. array_key_first() ו-array_key_last() אומרות לכם איזה מפתח ראשון או אחרון.

איך משנים ערכים במערך בתוך foreach ב-PHP?

עברו בלולאה דרך הפניה עם &: foreach ($prices as &$price) { $price *= 2; } unset($price);. או כתבו דרך המפתח: foreach ($prices as $key => $price) { $prices[$key] = $price * 2; }. $price = ... רגיל משנה רק עותק.

למה foreach עם הפניה ב-PHP משכפל את האיבר האחרון?

אחרי foreach ($arr as &$v), $v הוא עדיין הפניה לאיבר האחרון. foreach ($arr as $v) שני כותב אז כל ערך לתוך המקום האחרון הזה, ולכן בסוף הוא חוזר על הערך הלפני אחרון. קראו ל-unset($v); מיד אחרי לולאת ההפניה.

איך יוצאים מלולאת foreach ב-PHP?

break; עוצר את הלולאה מיד ו-continue; מדלג לאיבר הבא. בלולאות מקוננות, break 2; יוצא גם מהלולאה הפנימית וגם מהחיצונית.

איור של שפות התכנות ב-Coddy

ללמוד תכנות עם Coddy

להתחיל