
לולאת foreach ב-PHP
בפרק הקודם, הכרנו את לולאת for, מבנה בקרה שמבצע פעולות חוזרות בצורה סידרתית. כמו for, גם לולאת foreach היא מבנה בקרה שמאפשר ביצוע פעולות חוזרות בצורה סדרתית, כאשר היתרון שלה הוא במעבר סדרתי על מבני נתונים כמו מערכים, אובייקטים או מבנים מורכבים יותר, וזאת מבלי להתעסק עם אינדקסים.
כל הרצה של בלוק הקוד בלולאת foreach מכונה "איטרציה".
ישנם 2 אפשרויות לתחביר של לולאת foreach, נסקור אותם להלן.
לולאת foreach עם ערך בלבד
תחביר:
foreach ($array as $value) {
// Execute code for each value
}
הלולאה עוברת על כל איברי המערך array, איבר אחר איבר. בכל איטרציה, המשתנה value מקבל את ערך האיבר הרלוונטי.
דוגמה:
<?php
$animals = ["Cat", "Dog", "Elephant"];
foreach ($animals as $animal) {
echo "Animal: $animal\n";
}
?>
בדוגמה זו, אנו עוברים על המערך animals ומדפיסים את איברי המערך בזה אחר זה. נשים לב: המערך animals הוא מערך מבוסס אינדקסים ולא מערך אסוציאטיבי, כלומר, האיבר Cat באינדקס 0, האיבר Dog באינדקס 1 והאיבר Elephant באינדקס 2. לולאת ה-foreach אינה מתייחסת כלל לאינדקסים של איברי המערך ומטפלת בערכי האיברים בלבד.
לולאת foreach עם מפתח ועם ערך
תחביר:
foreach ($array as $key => $value) {
// Execute code using both key and value
}
הלולאה עוברת על כל איברי המערך array, איבר אחר איבר. בכל איטרציה, המשתנה key מקבל את המפתח של האיבר הרלוונטי, והמשתנה value מקבל את הערך של אותו האיבר.
דוגמה:
<?php
$person = ["name" => "Alice", "age" => 25, "city" => "Paris"];
foreach ($person as $key => $value) {
echo "$key: $value\n";
}
?>
בדוגמה זו, אנו עוברים על המערך person ומדפיסים את כל המפתחות והערכים שלו. נשים לב: המערך person הוא מערך אסוציאטיבי, כלומר, המפתחות שלו הם מחרוזות ולא אינדקסים מספריים. המפתח name כולל את הערך Alice, המפתח age כולל את הערך 25 והמפתח city כולל את הערך Paris.
מתי להשתמש בכל צורת תחביר
באופן עקרוני, ניתן להשתמש בשתי צורות התחביר של לולאת foreach בכל סוגי המערכים.
התחביר הראשון (לולאת foreach עם ערך בלבד) נועד בעיקר לעבודה עם מערכים המבוססים אינדקסים מספריים. אם נשתמש בתחביר זה עבור מערך אסוציאטיבי, לא נוכל לגשת בלולאה למפתחות של האיברים עליהם אנו עוברים בכל איטרציה.
התחביר השני (לולאת foreach עם ערך ומפתח) נועד בעיקר לעבודה עם מערכים אסוציאטיבים. אם נשתמש בתחביר זה עבור מערך מבוסס אינדקסים מספריים, ערך המשתנה key בלולאה יקבל את האינדקסים: 0, 1, 2 וכן הלאה.
כדי לקבוע באיזה תחביר להשתמש, פשוט נחשוב אם יש לנו צורך במפתחות בתוך הלולאה. אם אין צורך במפתחות, נשתמש בתחביר הראשון. אם יש צורך במפתחות, נשתמש בתחביר השני.
עדכון מבנה הנתונים בלולאת foreach
כאשר לולאת foreach עוברת על ערכי מערך, כל ערך הוא למעשה העתק של הערך המקורי. לכן, שינוי של הערך עצמו אינו משנה את המערך.
דוגמה:
<?php
$numbers = [10, 20, 30];
foreach ($numbers as $number) {
$number += 5;
}
print_r($numbers);
// Outputs:
// Array ( [0] => 10 [1] => 20 [2] => 30 )
?>
בדוגמה זו, המשתנה number מחזיק בכל איטרציה את הערך של האיבר הבא במערך. שינוי המשתנה number אינו משנה את המערך עצמו.
אם נרצה לשנות את המערך עצמו, נצטרך לעבוד עם התחביר השני ולשנות ישירות את המערך באמצעות המפתחות (או האינדקסים, במקרה של מערך מבוסס אינדקסים מספריים).
דוגמה:
<?php
$numbers = [10, 20, 30];
foreach ($numbers as $key=>$value) {
$numbers[$key] = $value += 5;
}
print_r($numbers);
// Outputs:
// Array ( [0] => 15 [1] => 25 [2] => 35 )
?>
בדוגמה זו, בכל איטרציה אנו ממש משנים את המערך עצמו לפי המפתח.
חלופה אפשרית שמאפשרת את עדכון המערך מבלי להתעסק עם המפתחות היא באמצעות סימן הרפרנס &.
דוגמה:
<?php
$numbers = [10, 20, 30];
foreach ($numbers as &$number) {
$number += 5;
}
unset($number); // Always unset the reference after use
print_r($numbers);
// Outputs:
// Array ( [0] => 15 [1] => 25 [2] => 35 )
?>
בדוגמה זו, המשתנה number אינו עותק של ערך האיבר הרלוונטי, כי אם רפרנס ישיר אליו. לכן, עדכון המשתנה number משנה ממש את ערך האיבר במערך.
חשוב לזכור: אם עובדים עם רפרנסים, יש למחוק את הרפרנס בסיום השימוש (כדי לשחרר את הזכרון שהוקצה לו, וכדי למנוע עדכון שלו בהמשך הקוד בטעות). נעשה זאת באמצעות הפקודה unset, כפי שראינו בדוגמה האחרונה.
קינון לולאות foreach
ניתן לבצע קינון של לולאת foreach, כלומר, להפעיל לולאה בתוך לולאה.
דוגמה:
<?php
$matrix = [
["A", "B", "C"],
["D", "E", "F"],
["G", "H", "I"]
];
foreach ($matrix as $row) {
foreach ($row as $element) {
echo "$element ";
}
echo "\n";
}
// Outputs:
// A B C
// D E F
// G H I
?>
בדוגמה זו, הגדרנו מערך דו מימדי בשם matrix. הלולאה החיצונית עוברת על 3 איברי המערך הראשיים, שכל אחד מהם הוא מערך חד מימדי הכולל 3 איברים. בכל איטרציה של הלולאה החיצונית, הלולאה הפנימית עושה 3 איטרציות, בהן היא עוברת על 3 איברי המערך החד מימדי. בסך הכל, הלולאה הפנימית רצה 9 פעמים.
ניתן לקנן לעומק גדול יותר מ-2 (לולאה בתוך לולאה בתוך לולאה וכן הלאה), ואף לשלב קינון של לולאות for עם לולאות foreach. עם זאת, מומלץ לא לסבך את מבנה הלולאות (קינון בעומק של יותר מ-2 או שילוב רב מדי של סוגי לולאות), כיוון שכך גדלים צריכת הזכרון וזמן הריצה.
הצהרות break ו-continue בלולאות foreach
הצהרת continue מדלגת על המשך האיטרציה הנוכחית של הלולאה, ועוברת לאיטרציה הבאה.
דוגמה:
<?php
$numbers = [10, 20, 30, 40, 50];
foreach ($numbers as $number) {
if ($number === 30) {
echo "Skipping number $number\n";
continue;
}
echo "Processing number: $number\n";
}
// Outputs:
// Processing number: 10
// Processing number: 20
// Skipping number 30
// Processing number: 40
// Processing number: 50
?>
הצהרת break מסיימת את ביצוע הלולאה.
דוגמה:
<?php
$numbers = [10, 20, 30, 40, 50];
foreach ($numbers as $number) {
if ($number === 30) {
echo "Number $number found! Exiting loop.\n";
break;
}
echo "Processing number: $number\n";
}
// Outputs:
// Processing number: 10
// Processing number: 20
// Number 30 found! Exiting loop.
?>
ניתן כמובן לשלב הצהרות break ו-continue באותה הלולאה.
דוגמה:
<?php
$numbers = [10, 20, 30, 40, 50];
foreach ($numbers as $number) {
if ($number === 20) {
echo "Skipping number $number\n";
continue;
}
if ($number === 40) {
echo "Number $number reached! Exiting loop.\n";
break;
}
echo "Processing number: $number\n";
}
// Outputs:
// Processing number: 10
// Skipping number 20
// Processing number: 30
// Number 40 reached! Exiting loop.
?>
נמליץ שלא לסרבל את הלולאות עם יותר מדי הצהרות break ו-continue, על מנת לא לפגוע בקריאות הקוד. כמו כן, כאשר משתמשים בהצהרות break ו-continue, נמליץ לשלב הערות עם הסבר בקוד: הסבר מדוע דילגנו לאיטרציה הבאה או מדוע סיימנו את הלולאה.
לולאת for לעומת לולאת foreach
ברוב המקרים, ניתן להמיר לולאת for בלולאת foreach ולהיפך.
היתרון של לולאת foreach, הוא שהקוד קריא יותר וקל יותר לתחזוקה ועבודה. זאת מכיוון שאין צורך לטפל באינדקסים. מנגד, היתרון של לולאת for הוא גמישות רבה יותר משל לולאת foreach, במיוחד בתרחישים בהם יש צורך בטיפול באינדקסים.
דוגמה:
<?php
// Using for
$numbers = [10, 20, 30];
for ($i = 0; $i < count($numbers); $i++) {
echo $numbers[$i] . "\n";
}
// Using foreach
foreach ($numbers as $number) {
echo $number . "\n";
}
?>
בדוגמה זו, ניתן לראות שהלולאה הראשונה עושה שימוש במשתנה הלולאה i, בודקת את גודל המערך באמצעות הפונקציה count ומגדירה תנאי סיום והגדלה. כל אלו לא נמצאים בלולאה השניה, לולאת ה-foreach, שהיא קריאה הרבה יותר.
אנו ממליצים להשתמש בלולאת foreach, כל עוד הדבר אפשרי ואינו נעשה בצורה מאולצת מדי.