آموزش حلقه foreach در PHP با مثال

یکی از روش‌های پرکاربرد برای پیمایش داده‌ها، ساختار foreach است. این حلقه به ما کمک می‌کند بدون درگیر شدن با شمارنده‌ها و indexها، روی عناصر آٰایه حرکت کنیم. در این آموزش به‌طور کامل با ساختار حلقه foreach در PHP آشنا شده و با مثال‌های مختلف، موقعیت‌ها و حالاتی که می‌توانیم از آن استفاده کنیم را می‌آموزیم.

در جلسه آموزش حلقه در PHP با چهار نوع حلقه اصلی که برای پیمایش داده‌ها وجود دارد آشنا شدیم. هر کدام از این حلقه‌ها کاربرد خاص خودشان را دارند و حتی ممکن است بتوانیم از آن‌ها به‌جای یکدیگر استفاده کنیم؛ اما برای حرکت روی آرایه‌ها، حلقه foreach بهترین و ساده‌ترین روش است.

  • for
  • foreach
  • while
  • do while

فرض کنید می‌خواهیم لیستی از نام‌ها را چاپ کنیم؛ یا جدول استان‌ها و مراکز آن‌ها را در صفحه سایت نمایش دهیم. در چنین شرایط که یک داده‌ی مجموعه‌ای (آرایه یا لیست) داریم و می‌خواهیم روی اعضای آن حرکت کنیم، foreach بسیار کاربردی است.

تعریف حلقه foreach در PHP

حلقه foreach در هر بار اجرا، به‌طور خودکار یکی از اعضای داده‌ی قابل پیمایش را درون یک متغیر قرار می‌دهد و ما به آن متغیر (تک‌تکِ اعضا) در بدنه حلقه دسترسی داریم. منظورم از داده قابل پیمایش، هر نوع داده‌ای و متغیر PHP است که بتوان روی آن حرکت کرد. شناخته‌شده‌ترینِ آن‌ها، آرایه است.

ساختار کلی foreach در PHP به شکل زیر است:

<?php foreach ($array as $item) {     // codes }

در این قطعه کد، $array همان آرایه یا داده قابل پیمایشی است که می‌خواهیم روی اعضای آن حرکت کنیم و $item در هر بار اجرای بدنه حلقه، برابر با یکی از اعضای آرایه است.

فرض کنید آرایه‌ای از اسامی داریم و می‌خواهیم آن‌ها را چاپ کنیم. واضح است که به‌جای چاپ کردن با echo، می‌توانیم هر کار و پردازش دیگری روی اعضا انجام دهیم. برای چاپ اعضا، مشابه قطعه کد زیر عمل می‌کنیم:

<?php $names = ["Sahar", "Moein", "Maryam", "Omid", "Milad"]; foreach ($names as $name) {     echo $name . "<br>"; }

خروجی قطعه کد بالا، ۵ خط حاوی اسامی درون آرایه $names است.

foreach روی آرایه کلید مقدار

یکی از قابلیت‌های مهم و کاربردی حلقه foreach در PHP این است که می‌توانیم همزمان به کلید و مقدار مربوطه‌ی هر عضو در آرایه دسترسی داشته باشیم. این حالت، بیشتر برای آرایه‌های انجمنی (آرایه‌های کلید-مقدار یا Associative Array) استفاده می‌شود.

فرض کنید آرایه‌ای نام استان‌ها و مراکز آن‌ها را داریم. یعنی نام استان به‌عنوان کلید و نام شهر مرکز استان به‌عنوان مقدار مربوط به هر کلید تعریف شده است. در قدم اول، می‌توانیم با حلقه foreach روی مقادیر (valueها) که همان شهرهای مرکز استان هستند حرکت کنیم. چیزی شبیه به قطعه کد زیر:

<?php $provinces = [     "Fars" => "Shiraz",     "Tehran" => "Tehran",     "Hormozgan" => "Bandar Abbas",     "Khorasan Razavi" => "Mashhad",     "Guilan" => "Rasht" ]; foreach ($provinces as $city) {     echo $city . "<br>"; }

خروجی این کد صرفاً اسامی شهرها را مشابه باکس زیر به ما می‌دهد:

Shiraz
Tehran
Bandar Abbas
Mashhad
Rasht

با ساختار دوم حلقه foreach می‌توانیم به‌طور همزمان هم به کلید و هم به مقدار دسترسی داشته باشیم. یعنی در مثال نام استان و مرکز، دو متغیر داریم که یکی نام استان و دیگری نام شهر مرکز استان است. به کد زیر توجه کنید:

<?php foreach ($provinces as $province => $city) {     echo "$province ($city)<br>"; }

تفاوت این حالت با ساختاری که قبل‌تر داشتیم این است که به‌جای نوشتن $city عبارت $province => $city را می‌نویسیم؛ چیزی شبیه به تعریف کلید و مقدار در آرایه انجمنی.

این‌گونه به حلقه foreach می‌گوییم که هر عضو را به صورت یک کلید و مقدار نگاه کن و سپس key => value را معادل متغیرهای $province و $city قرار بده و بدنه حلقه را اجرا کن. واضح است که $province و $city متغیر هستند و شما می‌توانید متناسب با نیازتان، هر نام دیگری برای این متغیرها در نظر بگیرید.

نمونه خروجی کد حلقه foreach روی آرایه انجمنی
نمونه خروجی کد حلقه foreach روی آرایه انجمنی

foreach روی آرایه اندیسی

از ساختار جدید (یعنی key => value) می‌توانیم روی آرایه‌های اندیسی (Indexed Array) که به طور ظاهری کلید ندارند هم استفاده کنیم. در این حالت، کلیدها همان شماره اندیس‌های هر عضو از آرایه هستند.

در قطعه کد زیر، آرایه $names را در ساختار کلید – مقداری فراخوانی کرده‌ام.

<?php $names = ["Sahar", "Moein", "Maryam", "Omid", "Milad"]; foreach ($names as $index => $name) {     echo "$index. $name<br>"; }

خروجی کد چیزی شبیه به زیر می‌شود:

0. Sahar
1. Moein
2. Maryam
3. Omid
4. Milad

می‌توانم با یک تغییر ساده، شماره اندیس را یکی اضافه کنم تا شماره‌گذاری لیست اسامی از 1 آغاز شود.

<?php $names = ["Sahar", "Moein", "Maryam", "Omid", "Milad"]; foreach ($names as $index => $name) {     echo ($index + 1). ". $name<br>"; }
خروجی مثال ساختاردهی چاپ آیتم‌ها در حلقه
خروجی مثال ساختاردهی چاپ آیتم‌ها در حلقه

پیشنهاد می‌شود نام‌هایی که برای آرایه‌ها و متغیرهای key و value انتخاب می‌کنیم، واضح و قابل فهم باشند. واضح است که هر اسمی برای این متغیرها بگذاریم، کدمان به درستی عمل می‌کند؛ اما بهتر است اسم‌های مرتبط و خوانایی انتخاب کنیم تا کدهای ما خواناتر و تمیزتر باشند.

آموزش آرایه در PHP و ترفندهای کار با آرایه

آموزش آرایه در PHP و ترفندهای کار با آرایه

تمرین و نکات حلقه foreach در PHP

مانند سایر حلقه‌ها، در بدنه حلقه foreach می‌توانیم هر دستوری را اجرا کرده و هر پردازشی را انجام دهیم. برای مثال می‌توانیم یک حلقه دیگر را درون آن بنویسیم و حلقه تودرتو (nested loop) داشته باشیم. یا اینکه از ساختارهای شرط در PHP درون آن استفاده کنیم.

<?php $names = ["Sahar", "Moein", "Maryam", "Omid", "Milad"]; foreach ($names as $name) {     if ($name === "Omid") {         echo "کاربر پیدا شد!";     } }

قطعه کد بالا، اگر مقدار عضوی که در حال پیمایش آن هستیم برابر با Omid باشد، پیام خاصی را چاپ می‌کند وگرنه کار دیگری انجام نمی‌دهد.

استفاده از break و continue

مشابه استفاده از دستورهای شرطی، می‌توانیم از دستورهای break و continue در حلقه foreach استفاده کنیم.

در اجرای حلقه‌ها، وقتی به دستور break می‌رسیدم، بدون توجه به اینکه تکرار چندم از اجرای حلقه است، اجرای حلقه متوقف می‌شد و به پایان می‌رسید. یعنی از حلقه خارج می‌شد و سایر کدهای پس از محدوده حلقه را اجرا می‌کرد. اگر با محدوده یا scope آشنا نیستید، آموزش اسکوپ در PHP را ببینید.

<?php $names = ["Sahar", "Moein", "Maryam", "Omid", "Milad"]; foreach ($names as $name) {     if ($name === "Omid") {         break;     }     echo "$name checked.<br>" }

در قطعه کد بالا، اگر به عضوی برسیم که مقدار آن Omid باشد، اجرای حلقه متوقف می‌شود. یعنی خروجی قطعه کد بالا، صرفاً حاوی سه اسم اول است.

Sahar
Moein
Maryam

در بدنه یک حلقه، وقتی به دستور continue می‌رسیم، به ابتدای تکرار بعدی حلقه می‌رویم. در نتیجه، سایر کدهای پس از دستور continue که درون بدنه حلقه وجود دارند برای آیتم فعلی اجرا نمی‌شود.

<?php $names = ["Sahar", "Moein", "Maryam", "Omid", "Milad"]; foreach ($names as $name) {     if ($name === "Omid") {         continue;     }     echo "$name checked.<br>" }

خروجی قطعه کد بالا مشابه زیر است. می‌بینید که وقتی مقدار آیتم برابر با Omid بوده، به تکرار بعدی رفته‌ایم و دستور echo برای این آیتم اجرا نشده است.

Sahar
Moein
Maryam
Milad

اگر با دستورهای break و continue آشنا نیستید، پیشنهاد می‌کنم حتماً آموزشش را ببینید:

استفاده از ارجاع (reference)

در حالت عادی، داخل بدنه حلقه foreach مقدار آیتم مورد نظر، فقط قابل خواندن است و نمی‌توانیم آن را تغییر دهیم.

فرض کنید می‌خواهیم کدی بنویسیم که بررسی کند اگر اسمی با M شروع شده بود، آن را تماماً با حروف بزرگ بازنویسی و جایگزین آیتم فعلی در آرایه کند. برای این کار احتمالاً کدی شبیه به زیر می‌نویسیم:

<?php $names = ["Sahar", "Moein", "Maryam", "Omid", "Milad"]; foreach ($names as $name) {     if (str_starts_with($name, "M")) {         $name = strtoupper($name);     } } print_r($names); // output: ["Sahar", "Moein", "Maryam", "Omid", "Milad"]

اما اگر آن را اجرا کنیم، می‌بینیم که اعضای آرایه $names هیچ تفاوتی نکرده‌اند. دلیلش آن است که ما صرفاً مقدار متغیر $name را تغییر داده‌ایم و نه مقدار آیتم مربوطه در آرایه را.

یادگیری PHP قدم به قدم از صفر
دوره جامع و رایگان آموزش PHP
می‌خوام الان شروع کنم!

۲ راهکار برای این چالش

برای حل این چالش، دو راه‌حل اصلی داریم:

راه حل اول این است که حلقه foreach در PHP را به روش دوم (یعنی key-value) بنویسیم. این‌گونه به اندیس هر آیتم دسترسی داریم و می‌توانیم در صورت نیاز، مقدار آن را به‌روزرسانی کنیم. در نتیجه، چیزی شبیه به قطعه کد زیر را خواهیم داشت:

<?php $names = ["Sahar", "Moein", "Maryam", "Omid", "Milad"]; foreach ($names as $index => $name) {     if (str_starts_with($name, 'M')) {         $names[$index] = strtoupper($name);     } } print_r($names);

از تابع str_starts_with() برای بررسی اینکه یک رشته با یک رشته خاص شروع شده یا نه و از strtoupper() برای تبدیل تمام حروف رشته به حروف بزرگ استفاده کرده‌ام. (آموزش رشته در PHP)

راه حل دوم این است که متغیر $name را با ارجاع (by reference) تعریف کنیم. برای این کار، قبل از نام متغیر، علامت & می‌گذاریم. حالا هر تغییری که روی این متغیر دهیم، در حافظه اصلی (که اعضای آرایه است) نیز اعمال می‌شود.

<?php $names = ["Sahar", "Moein", "Maryam", "Omid", "Milad"]; foreach ($names as &$name) {     if (str_starts_with($name, 'M')) {         $name = strtoupper($name);     } } print_r($names);

از این ساختار احتمالاً خیلی کم استفاده کنید، صرفاً توضیح دادم که با آن آشنا باشید. حواستان باشد که مقدار آخرین آیتم آرایه درون متغیر $name باقی می‌ماند و بهتر است آن را unset() کنیم. (توصیه مستندات انگلیسی)

نتیجه اجرای کد تغییر حروف به upper در foreach
نتیجه اجرای کد تغییر حروف به upper در foreach

در این آموزش، از آرایه برای مثالی از شیء قابل پیمایش استفاده کرده‌ام. اما هر ساختمان داده دیگری که قابل پیمایش باشد را می‌توانیم در ساختار حلقه‌ها تعریف و استفاده کنیم. برای مثال، می‌توانیم از شیءهایی که از یک کلاس اختصاصی ایجاد کرده‌ایم نیز در حلقه‌ها استفاده کنیم. (اگر با کلاس و مفهوم شیء آشنا نیستید، جلسه آموزش کلاس در PHP را ببینید.

مرور ۳ syntax حلقه foreach در PHP

در این آموزش با هر دو نوع ساختار foreach آشنا شدیم. این نوع حلقه، برای پیمایش روی آرایه‌ها و سایر داده‌های قابل پیمایش استفاده می‌شود.

برای مرور سریع، دو ساختار اصلی حلقه foreach در PHP به صورت‌های زیر بودند.

اولین syntax اینطور است که مقادیر موجود در آرایه را درون یک متغیر قرار داده و از آن در بدنه حلقه استفاده می‌کنیم.

<?php foreach ($array as $value) { ... }

دومین حالت زمانی کاربرد دارد که علاوه بر مقادیر، کلیدهای مرتبط با آن‌ها نیز برایمان اهمیت دارند. در این حالت از ساختاری شبیه به زیر استفاده می‌کنیم:

<?php foreach ($array as $key => $value) { ... }

مشابه اکثر دستورات PHP که محدوده آن‌ها با {} مشخص می‌شود، در حلقه foreach نیز می‌توانیم از علامت : برای شروع محدوده و از دستور endforeach برای پایانش استفاده کنیم. یعنی چیزی شبیه به ساختار زیر:

<?php foreach ($array as $item):     // loop body codes endforeach;

این ساختار معمولاً در کدهای ترکیبی با HTML خوانایی بهتری دارد.

امیدوارم این آموزش برای شما کاربردی بوده باشد و از این پس بتوانید به راحتی با حلقه foreach کار کنید. از این ساختار می‌توانید در بخش‌های مختلف مثل نمایش داده‌ها، پردازش داده‌های مجموعه‌ای، ایجاد مقادیر فیلدهای فرم PHP و هر جایی که نیاز به پیمایش روی داده‌ها دارید استفاده کنید.

اگر سؤالی دارید، در بخش دیدگاه‌ها مطرح کنید تا با هم گفت‌وگو داشته باشیم.

این آموزش بخشی از یک آموزش جامع و قدم به قدم در سبز دانش است: دوره رایگان آموزش PHP