foreach في PHP

من موسوعة حسوب
< PHP

(PHP 4, PHP 5, PHP 7)

تقدّم بنية foreach طريقة سهلة للتنقل بين عناصر المصفوفات، وتعمل هذه البنية مع المصفوفات والكائنات فقط، ويؤدي استخدامها مع متغير ذي نوع بيانات مختلف أو متغير غير مهيئ إلى إطلاق خطأ.

لهذه البنية صيغتان:

foreach (array_expression as $value)
    statement
foreach (array_expression as $key => $value)
    statement

تنتقل الصيغة الأولى عبر المصفوفة بحسب التعبير المقدّم إليها (array_expression). وفي كل دورة تسند اللغة قيمة العنصر الحالي إلى المتغير ‎$value ويتقدّم المؤشر الداخلي للمصفوفة إلى الأمام خطوة واحدة (أي أنك ستنظر إلى العنصر التالي في الدورة التالية).

تتيح الصيغة الثانية إجراء عملية إسناد إضافية وهي إسناد مفتاح العنصر الحالي إلى المتغير ‎$key في كل دورة.

تتيح PHP تخصيص دورات الكائنات.

ملاحظة: في PHP 5 يعاد تعيين مؤشر المصفوفة تلقائيًا إلى العنصر الأول في المصفوفة عند بدء تنفيذ عبارة foreach، وهذا يعني عدم الحاجة إلى استدعاء الدالة reset()‎ قبل حلقة foreach.

تعتمد حلقة foreach في عملها على المؤشر الداخلي للمصفوفة في PHP 5، ويؤدي تغيير هذا المؤشر داخل الحلقة إلى نتائج غير متوقعة، أما في PHP 7 فلا تعتمد foreach على المؤشر الداخلي للمصفوفة.

لإجراء التعديلات مباشرة على عناصر المصفوفة داخل الحلقة يمكن إلحاق العلامة & باسم المتغير، وهكذا تُسند القيمة إلى المتغير بالمرجعية.

<?php
$arr = array(1, 2, 3, 4);
foreach ($arr as &$value) {
    $value = $value * 2;
}
// $arr is now array(2, 4, 6, 8)
unset($value);
// إلغاء الإشارة مع العنصر الأخير
?>

تحذير: تبقى العلاقة المرجعية قائمة بين المتغير ‎$value وبين العنصر الأخير في المصفوفة حتى بعد الخروج من حلقة foreach، لذا ينصح بإلغاء هذه العلاقة باستخدام الدالة unset()‎، وإلا فإنك ستواجه الحالة الموضحة في المثال التالي.

بعد اكتمال حلقة foreach الأولى تأخذ عناصر المصفوفة القيم (2، 4، 6، 8) وتبقى العلاقة بين المتغير ‎$value والعنصر الأخير في المصفوفة قائمة ما لم تقطع بواسطة الدالة unset()‎.

في حلقة foreach الثانية ستُحدّث قيمة العنصر ‎$arr[3]‎ إلى القيم المأخوذة من المصفوفة ‎$arr، وفي النهاية تُنسخ قيمة العنصر ما قبل الأخير إلى القيمة الأخيرة:

<?php
$arr = array(1, 2, 3, 4);
foreach ($arr as &$value) {
    $value = $value * 2;
}

foreach ($arr as $key => $value) {
    // $arr[3] ستُحدَّث قيمة من المتغير $arr
    echo "{$key} => {$value} ";
    print_r($arr);
}

// المخرجات
// 0 => 2 Array ( [0] => 2, [1] => 4, [2] => 6, [3] => 2 )
// 1 => 4 Array ( [0] => 2, [1] => 4, [2] => 6, [3] => 4 )
// 2 => 6 Array ( [0] => 2, [1] => 4, [2] => 6, [3] => 6 )
// 3 => 6 Array ( [0] => 2, [1] => 4, [2] => 6, [3] => 6 )
?>

قبل الإصدار 5.5 من PHP كانت الإشارة إلى المتغير ‎$value ممكنة فقط في حال كانت المصفوفة قابلة للإشارة (بمعنى أنّها مسندة إلى متغير). الشيفرة التالية تعمل في الإصدار 5.5.0 من اللغة فقط:

<?php
foreach (array(1, 2, 3, 4) as &$value) {
    $value = $value * 2;
}
?>

ملاحظة: لا تدعم foreach القابلية على تجاوز رسائل الخطأ باستخدام العامل '@'.

لربما لاحظت أن الشيفرتين التاليتين متطابقتان تمامًا من الناحية العملية:

<?php
$arr = array("one", "two", "three");
reset($arr);
while (list(, $value) = each($arr)) {
    echo "Value: $value<br />\n";
}

foreach ($arr as $value) {
    echo "Value: $value<br />\n";
}
?>

الشيفرتان التاليتان متطابقتان أيضًا:

<?php
$arr = array("one", "two", "three");
reset($arr);
while (list($key, $value) = each($arr)) {
    echo "Key: $key; Value: $value<br />\n";
}

foreach ($arr as $key => $value) {
    echo "Key: $key; Value: $value<br />\n";
}
?>

إليك المزيد من الأمثلة لتوضيح طريقة الاستخدام:

<?php
// المثال 1: القيمة فقط

$a = array(1, 2, 3, 17);

foreach ($a as $v) {
    echo "Current value of \$a: $v.\n";
}

// المثال 2: القيمة مع صيغة الوصول اليدوية إلى عناصر المصفوفة لغرض التوضيح

$a = array(1, 2, 3, 17);

$i = 0;
// لغرض التوضيح فقط

foreach ($a as $v) {
    echo "\$a[$i] => $v.\n";
    $i++;
}

// المثال 3: المفتاح والقيمة


$a = array(
    "one" => 1,
    "two" => 2,
    "three" => 3,
    "seventeen" => 17
);

foreach ($a as $k => $v) {
    echo "\$a[$k] => $v.\n";
}

// المثال 4: مصفوفات متعددة الأبعاد

$a = array();
$a[0][0] = "a";
$a[0][1] = "b";
$a[1][0] = "y";
$a[1][1] = "z";

foreach ($a as $v1) {
    foreach ($v1 as $v2) {
        echo "$v2\n";
    }
}

// المثال 5: مصفوفات ديناميكية

foreach (array(1, 2, 3, 4, 5) as $v) {
    echo "$v\n";
}
?>

تفكيك المصفوفات المتداخلة باستخدام الدالة list()‎

(PHP 5 >= 5.5.0, PHP 7)

أتاح الإصدار 5.5 من اللغة التنقل عبر مصفوفة من المصفوفات وتفكيك المصفوفات المتداخلة إلى متغيرات في الحلقة وذلك باستخدام الدالة list()‎ كقيمة في الحلقة، فعلى سبيل المثال:

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

foreach ($array as list($a, $b)) {
// يحتوي المتغير الأول العنصر الأول من المصفوفة المتداخلة،
// أما المتغير الثاني فيضم العنصر الثاني.

    echo "A: $a; B: $b\n";
}
?>

تعطي الشيفرة السابقة المخرجات التالية:

A: 1; B: 2
A: 3; B: 4

يمكن تقديم عدد أقل من العناصر في الدالة list()‎ من تلك الموجودة في المصفوفة المتداخلة، وستهمل اللغة بقية القيم في المصفوفة:

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

foreach ($array as list($a)) {
    // لاحظ عدم وجود متغير ثانٍ
    echo "$a\n";
}
?>

تعطي الشيفرة السابقة المخرجات التالية:

1
3

سيظهر تنبيه في حال عدم وجود عناصر كافية لملء دالة list()‎:

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

foreach ($array as list($a, $b, $c)) {
    echo "A: $a; B: $b; C: $c\n";
}
?>

تكون مخرجات الشيفرة السابقة كالتالي:

Notice: Undefined offset: 2 in example.php on line 7
A: 1; B: 2; C: 

Notice: Undefined offset: 2 in example.php on line 7
A: 3; B: 4; C:

سجل التغييرات

الإصدار الوصف
7.0.0 لا تستخدم foreach المؤشر الداخلي للمصفوفة.
5.5.0 يمكن الإشارة إلى ‎$value في التعابير، أما في السابق فقد كانت المتغيرات وحدها هي المدعومة.
5.5.0 دعم تفكيك المصفوفات المتداخلة باستخدام الدالة list()‎.

مصادر