بخش پنجم: پیمایش آرایه‌ها با حلقه‌ها

۵-۱. مفهوم پیمایش

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

۵-۲. حلقه foreach

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

حالت اول: فقط مقدارها

<?php
$colors = ["قرمز", "سبز", "آبی"];

foreach ($colors as $color) {
    echo $color . "<br>";
}
?>

خروجی:

قرمز
سبز
آبی

در این ساختار، متغیر $color در هر تکرار مقدار یکی از عناصر آرایه را می‌گیرد.

حالت دوم: کلید و مقدار

<?php
$student = [
    "name"  => "علی",
    "age"   => 17,
    "field" => "کامپیوتر"
];

foreach ($student as $key => $value) {
    echo $key . " : " . $value . "<br>";
}
?>

خروجی:

name : علی
age : 17
field : کامپیوتر

در این ساختار، $key کلید و $value مقدار هر عنصر را می‌گیرد.

پیمایش آرایه دوبعدی با foreach

<?php
$students = [
    ["علی", 17],
    ["رضا", 18],
    ["مریم", 16]
];

foreach ($students as $row) {
    foreach ($row as $value) {
        echo $value . " | ";
    }
    echo "<br>";
}
?>

تغییر مقدار عناصر با foreach

برای تغییر مقدار عناصر آرایه در حلقه foreach، باید از علامت & (ارجاع) استفاده کنیم.

<?php
$numbers = [1, 2, 3, 4];

foreach ($numbers as &$number) {
    $number = $number * 2;
}

unset($number);

print_r($numbers);
?>

خروجی:

Array
(
    [0] => 2
    [1] => 4
    [2] => 6
    [3] => 8
)

نکته مهم: پس از پایان حلقه، متغیر ارجاعی ($number در مثال بالا) هنوز به آخرین عنصر آرایه اشاره می‌کند. برای جلوگیری از خطاهای بعدی، باید با unset آن را آزاد کرد.

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

۵-۳. حلقه for

حلقه for زمانی مناسب است که کلیدهای آرایه عددی و پیوسته باشند.

<?php
$colors = ["قرمز", "سبز", "آبی"];

for ($i = 0; $i < count($colors); $i++) {
    echo $colors[$i] . "<br>";
}
?>

خروجی:

قرمز
سبز
آبی

پیمایش آرایه دوبعدی با for

<?php
$students = [
    ["علی", 17],
    ["رضا", 18],
    ["مریم", 16]
];

for ($i = 0; $i < count($students); $i++) {
    for ($j = 0; $j < count($students[$i]); $j++) {
        echo $students[$i][$j] . " | ";
    }
    echo "<br>";
}
?>

محدودیت حلقه for

اگر کلیدهای آرایه پیوسته نباشند (مثلاً پس از حذف یک عنصر با unset)، حلقه for ممکن است به کلیدهای خالی برخورد کند و هشدار بدهد.

<?php
$colors = ["قرمز", "سبز", "آبی"];
unset($colors[1]);

// این حلقه برای کلید 1 هشدار می‌دهد
for ($i = 0; $i < count($colors); $i++) {
    echo $colors[$i] . "<br>";
}
?>

در چنین شرایطی، بهتر است از foreach استفاده شود یا کلیدها با array_values مرتب شوند.

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

<?php
$colors = ["قرمز", "سبز", "آبی"];
unset($colors[1]);

$keys = array_keys($colors);

for ($i = 0; $i < count($keys); $i++) {
    echo $colors[$keys[$i]] . "<br>";
}
?>

این روش مطمئن است، اما foreach ساده‌تر و خواناتر است.

۵-۴. حلقه while

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

روش اول: با شمارنده

<?php
$colors = ["قرمز", "سبز", "آبی"];
$i = 0;

while ($i < count($colors)) {
    echo $colors[$i] . "<br>";
    $i++;
}
?>

روش دوم: با توابع current، key، next و reset

PHP مجموعه‌ای از توابع برای حرکت دادن اشاره‌گر داخلی آرایه دارد. هر آرایه یک اشاره‌گر داخلی دارد که به یکی از عناصر اشاره می‌کند.

<?php
$colors = ["قرمز", "سبز", "آبی"];

reset($colors);

while (($key = key($colors)) !== null) {
    echo $key . " : " . current($colors) . "<br>";
    next($colors);
}
?>

خروجی:

0 : قرمز
1 : سبز
2 : آبی

توضیح توابع اشاره‌گر آرایه

تابع کار
reset اشاره‌گر را به اولین عنصر می‌برد و مقدار آن را برمی‌گرداند
current مقدار عنصر جاری را برمی‌گرداند
key کلید عنصر جاری را برمی‌گرداند
next اشاره‌گر را به عنصر بعدی می‌برد
prev اشاره‌گر را به عنصر قبلی می‌برد
end اشاره‌گر را به آخرین عنصر می‌برد

مطالعه تکمیلی: توابع اشاره‌گر آرایه در PHP قدیمی‌تر رایج بودند. در PHP جدید، استفاده از foreach توصیه می‌شود؛ زیرا خواناتر است و خطای کمتری دارد. همچنین توجه داشته باشید که در PHP 8، استفاده از current و key روی آرایه‌ای که اشاره‌گر آن به پایان رسیده باشد، مقدار false برمی‌گرداند. به همین دلیل در مثال بالا از !== null استفاده شده است، هرچند در برخی نسخه‌ها مقدار false برمی‌گردد و بهتر است از !== false استفاده شود.

۵-۵. مقایسه حلقه‌ها برای پیمایش آرایه

حلقه مناسب برای مزیت محدودیت
foreach همه انواع آرایه ساده، خوانا، بدون نیاز به شمارش تغییر مقدار نیاز به ارجاع دارد
for آرایه اندیس‌دار با کلیدهای پیوسته کنترل کامل روی شمارنده برای کلیدهای ناپیوسته مناسب نیست
while موارد خاص انعطاف بالا کد طولانی‌تر و خطاپذیرتر

توصیه کلی: برای پیمایش آرایه‌ها، در بیشتر موارد از foreach استفاده کنید.

۵-۶. پیمایش آرایه انجمنی با for

پیمایش آرایه انجمنی با for معمولاً توصیه نمی‌شود، اما با کمک array_keys امکان‌پذیر است.

<?php
$student = [
    "name"  => "علی",
    "age"   => 17,
    "field" => "کامپیوتر"
];

$keys = array_keys($student);

for ($i = 0; $i < count($keys); $i++) {
    echo $keys[$i] . " : " . $student[$keys[$i]] . "<br>";
}
?>

مطالعه تکمیلی: این روش فقط برای تمرین یا شرایط خاص کاربرد دارد. در عمل، foreach با ساختار $key => $value بسیار مناسب‌تر و خواناتر است.

۵-۷. پیمایش آرایه دوبعدی با کلید انجمنی

<?php
$students = [
    [
        "name"  => "علی",
        "age"   => 17
    ],
    [
        "name"  => "رضا",
        "age"   => 18
    ]
];

foreach ($students as $index => $student) {
    echo "دانش‌آموز " . ($index + 1) . ":<br>";
    foreach ($student as $key => $value) {
        echo $key . " : " . $value . "<br>";
    }
    echo "<hr>";
}
?>

۵-۸. شکستن و ادامه حلقه

استفاده از break

با break می‌توان حلقه را پیش از پایان طبیعی متوقف کرد.

<?php
$numbers = [10, 20, 30, 40, 50];

foreach ($numbers as $number) {
    if ($number == 30) {
        break;
    }
    echo $number . "<br>";
}
?>

خروجی:

10
20

استفاده از continue

با continue می‌توان از تکرار جاری صرف‌نظر کرد و به تکرار بعدی رفت.

<?php
$numbers = [10, 20, 30, 40, 50];

foreach ($numbers as $number) {
    if ($number == 30) {
        continue;
    }
    echo $number . "<br>";
}
?>

خروجی:

10
20
40
50

شکستن حلقه‌های تودرتو

با break و یک عدد، می‌توان چند حلقه تودرتو را همزمان شکست.

<?php
$students = [
    ["علی", 17],
    ["رضا", 18],
    ["مریم", 16]
];

foreach ($students as $row) {
    foreach ($row as $value) {
        if ($value == 18) {
            break 2;
        }
        echo $value . " ";
    }
}
?>

خروجی:

علی 17

مطالعه تکمیلی: استفاده از break با عدد (مثل break 2) کد را کوتاه می‌کند، اما خوانایی را کاهش می‌دهد. در برنامه‌های بزرگ بهتر است منطق برنامه به‌گونه‌ای طراحی شود که نیازی به شکستن چند سطحی نباشد.

۵-۹. مثال کامل

<?php
$products = [
    ["name" => "کیبورد", "price" => 450000],
    ["name" => "ماوس", "price" => 250000],
    ["name" => "مانیتور", "price" => 3500000]
];

$total = 0;

echo "<h3>لیست کالاها:</h3>";

foreach ($products as $index => $product) {
    echo ($index + 1) . ". " . $product["name"] . " - " . $product["price"] . " تومان<br>";
    $total += $product["price"];
}

echo "<hr>";
echo "جمع کل: " . $total . " تومان";
?>

۵-۱۰. نکات مهم

  1. foreach ساده‌ترین و مناسب‌ترین حلقه برای پیمایش آرایه است.
  2. برای دسترسی به کلید و مقدار با هم، از $key => $value استفاده می‌کنیم.
  3. برای تغییر مقدار عناصر در foreach، از ارجاع (&) استفاده می‌کنیم و پس از حلقه unset را فراخوانی می‌کنیم.
  4. حلقه for برای آرایه‌های با کلید پیوسته مناسب است.
  5. حلقه while با توابع اشاره‌گر آرایه امکان‌پذیر است، اما کمتر توصیه می‌شود.
  6. با break می‌توان حلقه را متوقف کرد و با continue از یک تکرار صرف‌نظر کرد.
  7. برای پیمایش آرایه‌های چندبعدی از حلقه‌های تودرتو استفاده می‌کنیم.
  8. در بیشتر موارد، foreach انتخاب اول است.