php 101 المصفوفات (Arrays) وحلقة foreach في PHP


عبد اللطيف ايمش

سنعلم في هذا الدرس عن المصفوفات وحلقة foreach.

arrays-in-php.png.804f45254f7db5324b6a44

لنفترض أنَّك تريد أن تُخزِّن مقدارًا كبيرًا من البيانات؛ أول 10000 من مضاعفات الرقم 5 على سبيل المثال، فعليك أنَّ تُعرِّف 10000 متغير لهم 10000 اسم؛ وهذه مهمة صعبة ومضنية بالتأكيد. أحد الحلول هو تخزين البيانات في مصفوفة، إذ يمكننا تخزين أي عدد نريده من القيم في مصفوفة وحيدة فقط! لنلقِ نظرةً عن آلية عمل المصفوفات.

<?php
// تعريف مصفوفة ذات ثلاثة عناصر
$type1 = array('first element', 'second element', 'third element');

// نستعمل الدالة print_r لطباعة جميع عناصر المصفوفة
// الناتج: Array ( [0] => first element [1] => second element [2] => third element ) 
print_r($type1);
    echo "<br>";

// نستعمل المفاتيح (الفهارس) للوصول إلى قيم معيّنة في المصفوفة
// لاحظ أنَّ المفاتيح رقمية من 0 حتى 2
echo $type1[0];
echo "<br>";
echo $type1[1];
echo "<br>";
echo $type1[2];
echo "<br>";
?>
  • في السطر الثالث من الشيفرة السابقة، عرَّفنا مصفوفةً اسمها ‎ $type1وملأناها بثلاث قيم (first element، و second element، و third element).
  • كيف يمكننا استعمالها الآن؟ كل قيمة من القيم المُخزَّنة في المصفوفة مرتبطة بمُعرِّف فريد يسمى الفهرس (index)؛ يمكنك الوصول إلى تلك القيم عبر الفهرس الخاص بها.
  • يطبع السطر السابع في المثال السابق المصفوفة بأكملها باستعمال الدالة print_r()‎، وسترى أنَّه على الرغم من أنَّك قد ملأت القيم فقط، لكنك ستحصل أيضًا على أرقامٍ تبدأ من الصفر وترتبط بتلك القيم؛ وفي الواقع، تلك الأرقام هي الرقم التسلسلي للقيمة (تذكر أننا نبدأ العد في البرمجة من الرقم 0 بدلًا من 1).
  • ثم قمنا بطباعة القيم التي خزناها في الموضع 0 و 1 و 2 على التوالي وبالترتيب.

المصفوفات الترابطية

استخدمنا الفهارس الافتراضية في المثال السابق (0، و 1، و2)، لكن يمكننا أن نُعرِّف الفهارس يدويًا كما في المثال الآتي:

<?php
// طريقةٌ أخرى لتعريف مصفوفة
$type2 = array('key'=>'value', 'key2'=>'value2', 'key3'=> 'value3');

// الناتج: Array ( [key] => value [key2] => value2 [key3] => value3 )
print_r($type2);
echo "<br>";
// المفاتيح هنا نصيّة، وهي key1، و key2، و key3
echo $type2['key3'];
?>

عرَّفنا في المثال السابق الفهارس الخاصة بنا (تُسمى أيضًا المفاتيح [keys]) التي ترتبط مع تلك القيم. يسمى هذا النوع من المصفوفات بالمصفوفات ترابطية (associative arrays).

الوصول إلى عناصر المصفوفات

تُعتبَر كل قيمة في المصفوفة متغيرًا مستقلًا، فيمكننا أن نجري جميع العمليات التي يمكن القيام بها على المتغيرات (كالزيادة والنقصان وإسناد القيم …إلخ.):

<?php
// نعرِّف مصفوفةً فارغةً
$arr = array();

// يمكننا إسناد البيانات إلى عناصر المصفوفة كما يلي
$arr[0] = 'academy';
$arr[1] = 'hsoub';

// قد لا تكون المفاتيح ذات أرقام متتالية (لاحظ عدم وجود المفتاحين 2 و 3)
$arr[4] = 'com';

// يمكننا استعمال نمطي المفاتيح (الرقمية والنصية) في نفس المصفوفة
$arr['day'] = 'Monday';
$arr['num1'] = 4;
$arr['num2'] = 5;

// كل عنصر في المصفوفة مستقل تمامًا عما سواه
$arr['num3'] = $arr['num1'] + $arr['num2'];

// سنطبع كامل المصفوفة باستعمال print_r
print_r($arr);
?>

لاحظ كيف أننا عرفنا بدايةً مصفوفةً فارغة، ثم أضفنا عناصرها بذكر المتغير الحاوي على مصفوفة متبوعًا بأقواسٍ مربعة ([]) بداخلها مفتاح العنصر. يجدر بالذكر أننا نستطيع أن نستعمل مفاتيح رقمية ونصية في نفس المصفوفة. 

إذا أردنا أن نجعل PHP تُرقِّم عناصر المصفوفة تلقائيًا عند إسناد قيم لها، فيكفي أن نضع أقواسًا مربعة فارغة كما يلي:

<?php
// نعرِّف مصفوفةً فارغةً
$arr = array();

// يمكننا جعل PHP تُرقِّم العناصر تلقائيًا كما يلي
$arr[] = 'academy';
$arr[] = 'hsoub';
$arr[] = 'com';

// سنطبع كامل المصفوفة باستعمال print_r
// الناتج: Array ( [0] => academy [1] => hsoub [2] => com )
print_r($arr);
?>

يجدر بالذكر أننا نستطيع أن ندرج قيمة عنصر من عناصر المصفوفة في سلسلةٍ نصيةٍ مباشرةً كما في المتغيرات (أي يجب أن تكون علامة الاقتباس مزدوجةً) لكن علينا في المصفوفات أن نحيط اسم العنصر بقوسين معقوفين كما يلي (لاحظ أننا استعملنا الطريقة الأكثر شيوعًا الآن في تعريف المصفوفات، ألا وهي إحاطة عناصر المصفوفة بقوسين مربعين [] كما يظهر في المثال أدناه): 

المصفوفات والحلقات

لنفترض أننا نريد إجراء بعض العمليات على كمية كبيرة من البيانات مخزَّنة في مصفوفة (ولنقل أننا نريد طباعة البيانات، أو حساب مجموع الأرقام الموجودة في المصفوفة)؛ فسنستعمل لهذا الغرض الحلقات، لنلقِ نظرةً على مثالٍ عن حلقة for:

<?php
$a = [1, 21, 23, 43, 32, 23, 4];
// عناصر المصفوفة هي: $a[0], $a[1], $a[2]...

// سنُهيِّئ متغيرًا للمجموع ونسند إليه القيمة 0
$sum = 0;

for($i = 0; $i < 7; $i++) {
  // ستزداد قيمة المتغير $i في كل تكرار للحلقة
  // أي أن قيمته ستتغير إلى قيمة مفتاح العنصر التالي في المصفوفة
  $sum += $a[$i];
}

echo $sum;
?>

أنصحك بأن تُعيد حلّ المثال السابق باستعمال حلقتَيّ while و do-while من درس الحلقات لكي تتدرب على استعمالها. 

هنالك حلقةٌ إضافيةٌ في PHP وُضِعَت خصيصًا للمصفوفات، اسمها حلقة foreach. إذ تبدأ هذه الحلقة من أول عنصر في المصفوفة وتنتهي بآخر عنصر فيها. لنعد كتابة المثال السابق باستخدام حلقة foreach:

<?php
$a = [1, 21, 23, 43, 32, 23, 4];
// عناصر المصفوفة هي: $a[0], $a[1], $a[2]...

// سنُهيِّئ متغيرًا للمجموع ونسند إليه القيمة 0
$sum = 0;

foreach ($a as $v) {
  // لو كنا نستعمل حلقة من نوع آخر، لكنا قد كتبنا
  // $v = $a[$i];
  // $sum += $v;
  // i++;
  $sum += $v;
}

echo $sum;
?>

نُسنِد -في كل تكرار للحلقة- قيمةً جديدةً للمتغير الذي اسمه ‎$v ونعطيه قيمة العنصر التالي في المصفوفة ‎$a؛ حلقة foreach مفيدة جدًا عندما لا تعرف عدد العناصر الموجودة في المصفوفة، أو إذا كنت تستعمل مصفوفة ترابطية (associative arrays).

حلقة foreach مع المصفوفات الترابطية

أما في حالة المصفوفات الترابطية، فعلينا تعريف متغيرين (بدلًا من واحد) لأننا لا نعلم قيمة الفهرس (أو المفتاح [key]) لكل عنصر. أول متغير نُعرِّفه هو المفتاح، والثاني هو القيمة التي ترتبط به. الشكل العام لحلقة foreach هو:

foreach (array as $key => $value) {
  statements
}

تمعّن في المثال الآتي وانظر كيف أُسنِد المفتاح إلى متغير، وأُسنِدَت قيمته إلى متغيرٍ آخر؛ يجدر بالذكر أنَّ المصفوفة المستعملة هي مصفوفة متعددة الأبعاد، أي أنَّ قيمة العنصر هي بدورها مصفوفةٌ أخرى، ولا مانع من استعمال حلقة foreach داخل حلقة foreach أخرى إن دعت الضرورة إلى ذلك.

<?php
// نُعرِّف مصفوفة ذات بعدين
$arr = [
  'student1' => array('SN' => 16472, 'math_grade' => 'A+'),
  'student2' => array('SN' => 16483, 'math_grade' => 'C'),
  'student3' => array('SN' => 16587, 'math_grade' => 'A')
];

// حلقة foreach تمر على جميع عناصر المصفوفة الرئيسية
foreach ($arr as $student => $info) {
  // لاحظ كيف أنَّ القيمة المُنسدَة إلى المتغير $info هي مصفوفة أخرى
  echo "the serial number for $student is {$info['SN']}, and he got {$info['math_grade']} grade in math!";
}
?>

دوال التعامل مع المصفوفات

ألم تتساءل كيف سنعلم إن كانت المصفوفة تحتوي عنصرًا ما أم لا؟ ربما فكرت باستعمال حلقةٍ ما للمرور على جميع عناصر المصفوفة، لكن PHP تسهِّل عليك الأمر وتوفر لك دالةً لاختبار وجود عنصرٍ ما في المصفوفة ألا وهي الدالةin_array() ‎ التي تقبل وسيطين أولهما هو القيمة التي سيُبحَث عنها، وثانيهما هي المصفوفة التي سيُبحَث فيها؛ وستعيد هذه الدالة القيمة TRUE إن وجِدَت تلك القيمة في المصفوفة، و FALSE خلا ذلك. 

أما لو أردت معرفة إن كان مفتاحٌ ما موجودًا في المصفوفة، فاستعمل الدالةarray_key_exists() ‎ التي تقبل وسيطين أيضًا أولهما هو المفتاح الذي يُبحَث عنه، وثانيهما هو المصفوفة التي سيُبحَث فيها؛ وستعيد هذه الدالة TRUE إن وجد ذاك المفتاح، و FALSE عدا ذلك. مثالٌ عن استعمالهما:

<?php
$arr = ['subdomain' => 'academy', 'domain' => 'hsoub', 'root_domain' => 'com'];

// التحقق إن كانت القيمة «hsoub» موجودةً في المصفوفة
if (in_array('hsoub', $arr)) {
  echo '"hsoub" value found';
}

if (array_key_exists('subdomain', $arr)) {
  echo '"subdomain" key found';
}
?>

هل تتذكر كيف قسّمنا السلاسل النصية إلى قسمين يفصل بينهما محرف معيّن في درس السلاسل النصية وحصلنا على الجزء الواقع بعد ذاك المحرف؟ الدالة explode()‎ تفعل المِثل، لكنها تُخزِّن الناتج في مصفوفة، حيث تقبل وسيطين أولهما هو السلسلة النصية التي تُمثِّل الفاصل بين عناصر المصفوفة، وثانيهما هو السلسلة النصية التي تريد تقسيمها؛ انظر إلى ناتج المثال الآتي لإزالة الغموض عن الكلام السابق:

<?php
$str = 'hsoub academy is the best academy ever';

// سنقسم السلسلة النصية السابقة عند كلمة is، ثم سنطبع مخرجاتها
$arr1 = explode('is', $str);
// الناتج: Array ( [0] => hsoub academy [1] => the best academy ever ) 
print_r($arr1);

// سنقسم السلسلة النصية السابقة عند كلمة academy، مما يُنتِج ثلاثة عناصر في المصفوفة
$arr2 = explode('academy', $str);
// الناتج: Array ( [0] => hsoub [1] => is the best [2] => ever )
print_r($arr2);
?>

أما لو أردت دمج عناصر المصفوفة وتحويلها إلى سلسلة نصية، فاستعمل الدالة implode()‎؛ التي لها شكلان عامان أحدهما يقبل وسيطًا وحيدًا هو المصفوفة التي تريد تحويلها إلى سلسلة نصية؛ والشكل الثاني يقبل وسيطين أولهما هو السلسلة النصية التي ستوضع بين عناصر المصفوفة وثانيهما هو المصفوفة التي تريد تحويلها إلى سلسلة نصية.

<?php
$arr = ['academy', 'hsoub', 'com'];

// إن استعملنا implode ذات الشكل الأول، فسنحصل على academyhsoubcom
$str1 = implode($arr);
echo $str1;

// أما لو استعملنا الشكل الثاني، ومررنا «.» كوسيط، فسنحصل على academy.hsoub.com
$str2 = implode('.', $arr);
echo $str2;
?>

يُلخِّص الجدول الآتي بعض دوال المصفوفات الشهيرة:.

الدالة شرحها
array_merge()‎
  • يُمرَّر إليها أكثر من مصفوفة كوسيط
  • مهمتها هي دمج تلك المصفوفات مع بعضها بعضًا وإعادة المصفوفة الناتجة
array_rand()‎‎
  • اختيار قيمة عشوائية واحدة أو أكثر
  • تقبل وسيطًا إجباريًا هو المصفوفة التي ستؤخذ القيمة العشوائية منها
  • ووسيطًا اختياريًا يُحدِّد عدد القيم التي ستُعاد
  • تُعيد سلسلةً نصيةً تحوي مفتاح العنصر العشوائي المُختار إن اختارت قيمةً عشوائيةً وحيدة
  • تعيد مصفوفة بمفاتيح العناصر العشوائية إن كان الوسيط الثاني أكبر من 1
()array_search
  • تبحث في المصفوفة عن قيمة مُعيّنة وستُعيد المفتاح المقابل لها إن وُجِدَت
  • تقبل وسيطين أولهما هو القيمة التي ستبحث عنها، وثانيهما هو المصفوفة التي سيُبحَث فيها
array_sum()‎
  • حساب مجموع القيم العددية في مصفوفة
  • تقبل وسيطًا وحيدًا هو المصفوفة المُراد حساب مجموع الأعداد فيها
()array_unique
  • تُزيل هذه الدالة جميع التكرارات في مصفوفة تُمرَّر إليها كوسيط
()count
  • ربما هذه من أهم الدوال السابقة، إذ تُعيد عدد العناصر الموجودة في مصفوفة تُمرَّر إليها كوسيط.
  • نستفيد كثيرًا من هذه الدالة في حلقة for إن لم نكن نعرف عدد عناصر المصفوفة
  • نستطيع أن نكتب:
for (int i=0; i<array.count(); i++) {}

تمرين

لديك المصفوفة الآتية باسم names:

Array
(
    [16472] => Ayham
    [16483] => Ameen
    [15789] => Bashir
)

والمصفوفة باسم grades:

Array
(
    [16472] => Array
        (
            [math] => 62
            [arabic] => 76
            [english] => 75
        )

    [16483] => Array
        (
            [math] => 85
            [arabic] => 71
            [english] => 82
        )

    [15789] => Array
        (
            [math] => 52
            [arabic] => 86
            [english] => 93
        )

)

اكتب برنامجًا يأخذ اسم الطالب ثم يطبع جميع علاماته.

المصادر





تفاعل الأعضاء


لا توجد أيّة تعليقات بعد



يجب أن تكون عضوًا لدينا لتتمكّن من التعليق

انشاء حساب جديد

يستغرق التسجيل بضع ثوان فقط


سجّل حسابًا جديدًا

تسجيل الدخول

تملك حسابا مسجّلا بالفعل؟


سجّل دخولك الآن