البحث في الموقع
المحتوى عن 'مصفوفات'.
-
نتعامل في تطوير الويب مع البيانات بالصيغة الثنائية لما نتعامل مع الملفات، سواءً عند إنشائها أو رفعها أو تنزيلها، كما يمكن استخدامها في عمليات معالجة الصور، ويمكن إنجاز كل ما سبق في JavaScript التي تتميز العمليات الثنائية فيها بأنها عالية الأداء على الرغم من وجود بعض الالتباسات، نظرًا لوجود العديد من الأصناف، منها ArrayBuffer وUint8Array وDataView وBlob وFile، وغيرها. لا توجد طريقة معيارية للتعامل مع البيانات الثنائية في JavaScript موازنةً بغيرها من اللغات، لكن عندما نصنف الأمور فسيبدو كل شيء بسيطًا نوعًا ما، إذ يمثل الكائن الثنائي الأساسي ArrayBuffer مثلًا مرجعًا إلى مساحة ذاكرة متجاورة وذات حجم محدد، ويمكن إنشاؤه كالتالي: let buffer = new ArrayBuffer(16); // إنشاء مخزن مؤقت حجمه 16 alert(buffer.byteLength); // 16 حيث تحجز الشيفرة السابقة حجمًا من الذاكرة مقداره 16 بايت، ويُملأ بالأصفار. فالكائن ArrayBuffer هو مساحة من الذاكرة التي لا يمكن معرفة ما يُخزّن فيها، بل هي سلسلة خام من البايتات، وللتعامل مع ArrayBuffer، سنحتاج إلى كائن عرض لا يخزن أي بيانات بمفرده، بل تنحصر مهمته في تفسير البايتات المخزنة في ArrayBuffer، ومن بين هذه الكائنات الآتي: "Uint8Array": يعامِل كل بايت من ArrayBuffer مثل عدد مستقل يأخذ قيمةً بين 0 و255، وتُمثِّل عددًا صحيحًا بلا إشارة مؤلفًا من 8-بت. "Uint16Array": يعامِل كل بايتين مثل عدد صحيح يأخذ قيمةً بين 0 و65535، وتمثِّل عددًا صحيحًا بلا إشارة مؤلفًا من 16-بت. "Uint32Array": يعامِل كل 4 بايتات مثل عدد صحيح يأخذ قيمةً بين 0 و4294967295، وتمثل عددًا صحيحًا بلا إشارة مؤلفًا من 16-بت. "Float64Array": يعامل كل 8 بايتات مثل عدد عشري ذي فاصلة عائمة floating-point، ويأخذ قيمةً بين 5.0x 10^-324 و1.8x 10^308. وبالتالي سيفسَّر الكائن المؤلف من 16 بايت -وفق الكائنات السابقة- إلى 16 عدد صغير، أو 8 أرقام أكبر (بايتان لكل عدد)، أو 4 أعداد أضخم (4 بايتات لكل عدد)، أو عددين بالفاصلة العائمة عاليي الدقة (8 بايتات لكل منهما). فالكائن ArrayBuffer هو الكائن البنيوي وأساس البيانات الخام. ولا بدّ من استخدام كائن عرض عند محاولة الكتابة ضمنه أو المرور على قيمه وكذلك لأي عملية بالأساس، مثلًا: let buffer = new ArrayBuffer(16); // إنشاء مخزن مؤقت من 16 بايت let view = new Uint32Array(buffer); // تعامل مع المخزن كعدد صحيح من 32-بت alert(Uint32Array.BYTES_PER_ELEMENT); // أربعة بايت لكل عدد alert(view.length); // 4 alert(view.byteLength); // 16 // كتابة قيمة view[0] = 123456; // المرور على قيمه for(let num of view) { alert(num); // 123456, then 0, 0, 0 (أربعة قيم ككل) } الكائن TypedArray إنّ المصطلح الرئيسي لكائنات العرض السابقة هو مصفوفات النوع TypedArray، والتي تشترك جميعها بمجموعة التوابع والخصائص، مع ملاحظة عدم وجود دالة بانية اسمها TypedArray، فهو مجرد مصطلح يمثِّل كائنات العرض السابقة التي تطبق على ArrayBuffer، وهي Int8Array وUint8Array، وغيرها من الكائنات، وسنتابع بقية القائمة لاحقًا. عندما نرى أمرًا وفق الصيغة new TypedArray، فقد يعني ذلك أيًا من new Int8Array أو new Uint8Array وغيرها، إذ تسلك مصفوفات النوع سلوك بقية المصفوفات، فلها فهارس indexes ويمكن المرور على عناصرها، كما يختلف سلوكها باختلاف نوع الوسائط التي تقبلها، وهناك 5 حالات ممكنة للوسائط: new TypedArray(buffer, [byteOffset], [length]); new TypedArray(object); new TypedArray(typedArray); new TypedArray(length); new TypedArray(); إذا أضيف وسيط من النوع ArrayBuffer فسيتشكل كائن عرض موافق له، وقد استخدمنا هذه الصيغة سابقًا. يمكن أن نختار إزاحةً byteOffset لنبدأ منها (ولها القيمة 0 افتراضيًا)، وأن نحدد حجمًا محددًا length من المخزن (وسيكون حجم المخزن الكلي هو القيمة الافتراضية)، وبهذا سنغطي جزءًا من المخزن المؤقت buffer فقط. عندما نضع وسيطًا على شكل مصفوفة Array أو أي كائن شبيه بها، فستُنشِئ مصفوفةَ نوع لها نفس الحجم وتنسخ المحتويات إليها، ويمكن استخدام ذلك لملء المصفوفة مسبقًا بالبيانات: let arr = new Uint8Array([0, 1, 2, 3]); alert( arr.length ); // 4, ينشئ مصفوفة ثنائية لها الحجم نفسه alert( arr[1] ); // 1,لها القيم نفسها (unsigned 8-bit integers) يملؤها بـ 4 بايتات من النوع لو استخدمنا مصفوفة نوع TypedArray من نوع مختلف، فستُنشَأ مصفوفة نوع لها نفس الحجم وتنسخ المحتويات إليها، وستحوَّل القيم إلى النوع الجديد خلال العملية عند الحاجة لذلك، مثلًا: let arr16 = new Uint16Array([1, 1000]); let arr8 = new Uint8Array(arr16); alert( arr8[0] ); // 1 alert( arr8[1] ); // 232, tried to copy 1000, but can't fit 1000 into 8 bits (explanations below) يُنشئ الوسيط العددي length مصفوفة نوع تحتوي عدد عناصر مساويًا لقيمته، أما طولها بالبايت فسيكون مساويًا للقيمة length مضروبةً بعدد البايتات اللازم لتمثيل أحد عناصرها TypedArray.BYTES_PER_ELEMENT، مثلًا: let arr = new Uint16Array(4); // integer إنشاء مصفوفة نوع تحوي 4 أعداد من النوع alert( Uint16Array.BYTES_PER_ELEMENT ); // بايتان لكل عدد alert( arr.byteLength ); // حجمها 8 بايت عندما لا نستخدم أي وسائط، فستتشكل مصفوفة نوع طولها 0. يمكن إنشاء مصفوفة نوع مباشرةً دون الإشارة إلى الكائن ArrayBuffer، لكن كائن العرض لا يتشكل دون وجود الكائن الأساسي ArrayBuffer، وبالتالي سيتشكل كائن التخزين المؤقت أوتوماتيكيًا في الحالات السابقة كلها عدا الحالة الأولى (عندما ننشئه نحن). سنستخدم الخصائص التالية للوصول إلى الكائن ArrayBuffer: arr.buffer: يعيد مرجعًا إلى الكائن ArrayBuffer. arr.byteLength: يعيد طول الكائن ArrayBuffer. وبالتالي يمكننا الانتقال من كائن عرض إلى آخر، مثلًا: let arr8 = new Uint8Array([0, 1, 2, 3]); // كائن عرض آخر للمعطيات نفسها let arr16 = new Uint16Array(arr8.buffer); إليك قائمةً بمصفوفات النوع: "‘Uint32Array" و"Uint16Array" و"Uint8Array": تستخدم للأعداد الصحيحة 8 و16 و32 بت. "Uint8ClampedArray": لتمثيل الأعداد الصحيحة ذات 8-بت، وتبقي القيمة 0 أو 255 إن كانت خارج المجال. "‘Int32Array" و"Int16Array" و"Int8Array": لتمثيل الأعداد الصحيحة السالبة أو الموجبة. "Float32Array" و"Float64Array": لتمثيل الأعداد العشرية ذات 32 و64 بت والتي تحمل إشارةً بطريقة الفاصلة العائمة. سلوك المصفوفات عند خروج القيم عن حدودها عندما نحاول كتابة قيمة خارج حدود مصفوفة النوع فلن يظهر لنا خطأ، لكن ستُحذف البتات الزائدة. لنحاول مثلًا وضع القيمة 256 ضمن Uint8Array، فإذا حولنا 256 إلى الصيغة الثنائية، فستكون بالشكل "100000000" (9 بتات)، لكن النوع الذي استخدمناه يحوي 8 بتات فقط، أي قيمًا بين 0 و255، وفي حال أدخلنا رقمًا أكبر من النطاق السابق فستُخزن الخانات اليمينية الثمان (الأقل قيمة) فقط ويُحذف الباقي، وبالتالي سنحصل على القيمة 0 في هذا المثال. لنأخذ العدد 257 مثالًا آخر لذلك، أينما سنحصل ثنائيًا على تسع بتات "100000001"، ستُخزّن منها الخانات اليمينية الثمان الأولى، وسنحصل بالنتيجة على القيمة 1. let uint8array = new Uint8Array(16); let num = 256; alert(num.toString(2)); // 100000000 (التمثيل الثنائي) uint8array[0] = 256; uint8array[1] = 257; alert(uint8array[0]); // 0 alert(uint8array[1]); // 1 للنوع Uint8ClampedArray ميزة خاصة، فهو يعطي القيمة 255 لأي عدد أكبر من 255، والقيمة 0 لأي عدد سالب، وهذا مفيد في معالجة الصور. توابع الصنف TypedArray لهذا الصنف نفس توابع المصفوفات مع بعض الاستثناءات الواضحة، حيث يمكننا مسح عناصره، وتنفيذ التوابع map وslice وfind وreduce؛ إلا أنه لا يمكن تنفيذ عدة أشياء، منها الآتي: لا يمكن استخدام التابع splice: لا يمكن "حذف" قيمة ما، لأنّ مصفوفات النوع هي كائنات تعرض مساحات ثابتةً متجاورةً من الذاكرة مؤقتًا، وكل ما يمكننا فعله هو إسناد القيمة 0 لها. لا يمكن استخدام التابع concat. كما يوجد تابعان إضافيان: ([arr.set(fromArr, [offset: ينقل عناصر المصفوفة fromArr إلى arr ابتداءً من الموقع offset، والذي يأخذ القيمة 0 افتراضيًا. ([arr.subarray([begin, end: يُنشئ كائن عرض جديد من نفس النوع بين القيمتين begin وend ضمنًا، وهذا يشبه التابع slice المدعوم أيضًا، لكنه لا ينسخ أي قيم، بل ينشئ كائن عرض جديد للتعامل مع جزء محدد من البيانات. تتيح لنا التوابع السابقة نسخ مصفوفات النوع ودمجها وإنشاء مصفوفات جديدة من مصفوفات موجودة مسبقًا وغيرها. الكائن DataView يمثل الكائن DataView كائن عرض عالي المرونة بلا نوع untyped للكائن ArrayBuffer، حيث يسمح بالوصول إلى البيانات ابتداءً من أي موضع وبأي تنسيق. تحدِّد الدالة البانية تنسيق البيانات في مصفوفات النوع، ويُفترض أن تكون الدالة منتظمةً ككل، وأن نحصل على العنصر الذي ترتيبه "i" باستخدام التعليمة [arr[i. يمكن الوصول إلى البيانات عند استخدام DataView من خلال توابع مثل (getUint8(i. أو (getUint16(i.، ونختار التنسيق عند استدعاء التابع وليس عند إنشائه. نستخدم DataView كالتالي: new DataView(buffer, [byteOffset], [byteLength]) buffer: ويمثل الكائن ArrayBuffer الأساسي، ولا تنشئ DataView مخزنًا مؤقتًا خاصًا بها على عكس مصفوفات النوع، وإنما ينبغي أن يكون موجودًا مسبقًا. byteOffset: ويمثل بايت البداية لكائن العرض (القيمة الافتراضية 0). byteLength: عدد بايتات كائن العرض (إلى نهاية المخزن افتراضيًا). في المثال التالي نستخرج أعدادًا بتنسيقات مختلفة من المخزن ذاته: // مصفوفة ثنائية مكونة من 4 بايتات، وستكون أكبر قيمة 255 let buffer = new Uint8Array([255, 255, 255, 255]).buffer; let dataView = new DataView(buffer); // الحصول على رقم 8 بت عند الإزاحة 0 alert( dataView.getUint8(0) ); // 255 // الحصول على رقم 16 بت عند الإزاحة 0 alert( dataView.getUint16(0) ); // 65535 (biggest 16-bit unsigned int) // الحصول على رقم 32 بت عند الإزاحة 0 alert( dataView.getUint32(0) ); // 4294967295 (biggest 32-bit unsigned int) dataView.setUint32(0, 0); // إعطاء القيمة 0 لرقم من 4 بايت، وبالتالي تصفير المخزن تَظهر قدرة DataView عند تخزين أرقام ذات تنسيق مختلف في المخزن المؤقت نفسه، فلو خزّنّا مثلًا سلسلةً من البيانات مؤلفةً من الأزواج (عدد صحيح 16 بت، عدد عشري عائم 32 بت)، فسيسمح لنا DataView بالوصول إليها بكل سهولة. الخلاصة يمثل الكائن الأساسي ArrayBuffer مرجعًا إلى حجم ثابت ومتجاور في الذاكرة. نحتاج إلى كائن عرض لتنفيذ أي عملية على ArrayBuffer، ومن هذه الكائنات: مصفوفة النوع، والتي يمكن أن تكون: Uint8Array وUint16Array وUint32Array: وهي أعداد بلا إشارة من 8 أو 16 أو 32 بت. Uint8ClampedArray: أعداد صحيحة من 8 بت، مع اجتزاء البتات التي تزيد عن 8. Int8Array وInt16Array وInt32Array: أعداد صحيحة ذات إشارة. Float32Array وFloat64Array: أعداد بفاصلة عائمة من 32 أو 64 بت، وذات إشارة. الكائن DataView: ويستخدم التوابع لتحديد تنسيق الأعداد في مخزن مؤقت للبيانات، مثل (getUint8(offset. في معظم الأحيان يمكن العمل مباشرةً على مصفوفات النوع محتفظين بالكائن ArrayBuffer خلف الستار، ويمكن الوصول إليه باستخدام الأمر buffer.، كما يمكن إنشاء كائن عرض جديد عند الحاجة. يوجد مصطلحان إضافيان يستخدَمان في وصف التوابع التي تتعامل مع البيانات الثنائية: ArrayBufferView: وهو مصطلح يغطي كل أنواع كائنات العرض. BufferSource: مصطلح يغطي كلًا من ArrayBuffer أو ArrayBufferView، وسنرى هذه المصطلحات في الفصول القادمة، BufferSource من المصطلحات الشائعة، ويعني "أي نوع من البيانات الثنائية" سواءً كانت الكائن ArrayBuffer أو أي كائن عرض له. مهمات للإنجاز ضم مصفوفات النوع Concatenate typed arrays لنفترض وجود مصفوفة من النوع Uint8Array، يمكن استخدام الدالة (concat(arrays لضمّ عدة مصفوفات في مصفوفة واحدة. الحل إليك الحل المتمثل بالشيفرة التالية: function concat(arrays) { // مجموع أطوال كل مصفوفة let totalLength = arrays.reduce((acc, value) => acc + value.length, 0); if (!arrays.length) return null; let result = new Uint8Array(totalLength); // انسخ محتوى كل مصفوفة إلى الناتج result // يُنسخ محتوى المصفوفة اللاحقة على الجانب الأيمن للمصفوفة السابقة let length = 0; for(let array of arrays) { result.set(array, length); length += array.length; } return result; } افتح الحل في تجربة حية ترجمة -وبتصرف- للفصل Array buffer, Binary data من سلسلة The Modern JavaScript Tutorial. اقرأ أيضًا المقال السابق: هجمات الاختطاف بالنقر Clickjacking في جافاسكريبت هياكل البيانات: الكائنات والمصفوفات في جافاسكريبت معالجة المصفوفات Arrays في جافا المصفوفات ثنائية البعد Two-dimensional Arrays في جافا البحث والترتيب في المصفوفات Array في جافا
-
سنعلم في هذا الدرس عن المصفوفات وحلقة foreach. لنفترض أنَّك تريد أن تُخزِّن مقدارًا كبيرًا من البيانات؛ أول 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; ?> يُلخِّص الجدول الآتي بعض دوال المصفوفات الشهيرة:. table{border: 1px solid, black; border-collapse: collapse;} th, td{border: 1px solid black;padding: 5px 10px;} th{background-color: #fbfcfc;} الدالة شرحها 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 ) ) اكتب برنامجًا يأخذ اسم الطالب ثم يطبع جميع علاماته. المصادر مقال Array and foreach loop in PHP لصاحبه Harish Kumar. كتاب تعلم البرمجة بلغة PHP. صفحات Arrays و array وما هو موجود في Array Functions.
-
إذا أردت أن تصبح مطوّر ووردبريس فهذا يتطلب أيضًا تعلم لغة البرمجة الشهيرة PHP، والتي بنيت من خلالها منصة ووردبريس. طورت بشكل أساسي في عام 1994، PHP لغة برمجة قوية ومفتوحة المصدر لإنشاء مواقع ويب ديناميكية وتفاعلية. سوف تتعلم القواعد الأساسية للغة PHP وكيفية كتابتها، وكيفية عملها، والاطلاع على بعض الأمثلة. ما هي PHP؟ PHP هي لغة برمجة نصية من طرف الخادم (server). لفهم ما يعني هذا، لنقارنها مع Html. عندما تزور صفحة Html بسيطة، يقوم متصفحك بإرسال طلب للخادم الذي يحتوي هذه الصفحة التي تحاول الوصول إليها. الخادم يكتشف أي ملف تريد الوصول إليه ويقوم بإرساله لك. متصفحك يترجم شيفرة Html المرسلة ويعرضها لك. بالمقارنة، عندما تزور صفحة PHP هناك خطوة إضافية متصفحك يقوم بإرسال طلب والخادم يجد الملف الذي تريده. قبل إرساله لمتصفحك، الخادم يعالج الملف، منتجًا مخرجات Html نهائية (Html output) ثم يقوم بإرسال هذه المخرجات لمتصفحك الذي يقوم بعرضها كالمعتاد. لهذا السبب عندما تنظر إلى الشيفرة المصدرية لأي موقع لا ترى أبدًا أي شيفرات PHP، فقط Html، حتى لو كان الموقع مكتوبًا بلغة PHP. إذا لماذا يحتاج الخادم إلى عملية المعالجة؟ ما المغزى من ذلك؟ لأنه يمكننا من عمل مواقع ديناميكية وكتابة شيفرات بفعالية كبيرة. لنستعرض مثالين بسيطين. في Html كل شيء ثابت (static). يمكنك إنشاء صفحة تعرض كلمة “Good morning” أو “Good evening” لكنك لا تستطيع إظهار واحدة وإخفاء الأخرى اعتمادًا على التوقيت الحقيقي لليوم. في PHP تستطيع عمل ذلك لأن الخادم يمكنه معالجة التعليمات البرمجية آخذًا التوقيت الحقيقي لليوم بعين الاعتبار. والمنطق لهذا المثال يكون كالتالي: if it is before 10am { <h1>Good Morning</h1> } if it is after 6pm { <h1>Good Evening</h1> } otherwise { <h1>Good Day</h1> } طبعًا هذه ليست التعليمات البرمجية الحقيقية، لكنها تتبع منطق PHP. الخادم سيحدد أي حالة هي الحالة المحققة للشرط وسيعرض واحدة فقط من العناوين. مثال آخر هو موقع تويتر أو أي موقع آخر الذي يقدم المحتوى المكتوب من قبل المستخدمين. إذا كان تويتر يستخدم Html فقط، أحد ما يجب عليه أن يقوم بوضع تغريدتك في ملف Html في كل مرة تقوم بتغريدة جديدة وهذا طبعًا ليس استغلالاً جيدًا للوقت. يوجد حوالي 1 مليار حساب على موقع تويتر لذلك الشركة ستحتاج إلى 1 مليار ملف Html، ملف لكل مستخدم. مع PHP، مشكلة إعادة توليد ما ينشره المستخدم يمكن أن يحل بعدة ملفات. سنعود إلى هذا المثال لاحقًا في هذه المقالة. البداية قبل أن نبدأ، أود التنبيه على أنه في المراحل الأولى من تعلم PHP ربما لن تكون على قادرًا على إنشاء موقع ويب. هذه ردة فعل طبيعية وهذا أيضًا ما شعرت به عند بداية تعلم PHP. الخطوات الأولى تجريدية قليلاً، لكن في نهاية هذا المقال سترى النور. من أجل اختبار وممارسة ما سوف تتعلم في هذه المقالة، سوف تحتاج إلى خادم أباتشي (Apache server). يمكن أن يكون هذا موقع اختبار عبر الإنترنت ولكن يمكن أيضًا أن يكون خادم محلي. أوصي بإنشاء خادم محلي (local server). وإليك كيفية القيام بذلك: أولاً، عليك تحميل وتثبيت Virtualbox وVagrant. إنشاء مسار في أي مكان على كمبيوترك لتخزين ملفات المشروع. لدي مجلد “websites” في مسار المستخدم الخاص بي، قمت بإنشاء مسار “PHPtutorial”. وسوف أشير إلى هذا باسم “مجلد المشروع الرئيسي” طوال بقية هذا المقال. بمجرد إنشاء المسار، افتح terminal على linux أو osx، أو cmd على windows، وانتقل إلى المجلد. إذا قمت بإنشاء بنية المجلد نفسه كما لدي، على linux أو osx يمكنك كتابة cd ~/websites/PHPtutorial على windows cd %HOMEPATH%/websites/PHPtutorial عندما تكون في المسار الصحيح، ألصق الأمر التالي: curl -L -o 'install.sh' http://bit.ly/1hBfq57 && curl -L -o 'Vagrantfile' http://bit.ly/1mE3Qt9 && vagrant up وبمجرد تنفيذ الأمر، سوف تكون قادرًا على الوصول إلى الموقع الخاص بك على http://192.168.33.21. إذا قمت بإعادة تشغيل جهاز الكمبيوتر الخاص بك، سوف تحتاج أيضًا إلى إعادة تشغيل الخادم الخاص بك، والتي يمكنك القيام به عن طريق الانتقال إلى مجلد المشروع الرئيسي في سطر الأوامر وكتابة vagrant up. ملف المشروع الرئيسي هو الآن المجلد الجذر الخاص بك. قم بإنشاء ملف index.html هناك مع أي محتوى، وينبغي أن يتم عرضه بشكل صحيح عند زيارة موقع الويب الخاص بك على http://192.168.33.21. الخطوات الأولى في البداية، لنلقِ نظرة على الوسوم(tags)، المتغيرات(variables)، القيم (values)، والإظهار (echoing). أنشئ ملف اسمه index.php في ملف المشروع الرئيسي واكتب”Hello HTML” بداخله. للتأكد بأنه يعمل قم بزيارة http://192.168.33.21، ويجب رؤية النص الذي قمت بكتابته على شاشة المتصفح. قاعدة مهمة جدًا وهي أن ما يكتب داخل وسوم php يعتبر شيفرة PHP، وأي شيء آخر يعتبر Html. لذلك ظهر نص Hello HTML. وسوم php تبدأ ب<?php وتنتهي ب ?>. أي شيء بين هذين الوسمين يعتبر PHP. Hello HTML <?PHP echo "Hello PHP"; ?> التعليمات البرمجية السابقة أظهرت كيف يتم استخدام وسوم php وكيفية إظهار القيم على الشاشة. عندما تُظهر قيمة أنت تخبر PHP لعرض هذه القيمة على الشاشة. نتيجة تنفيذ التعليمات البرمجية السابقة سيكون ” Hello Html Hello PHP” . الجزء الأول يعتبر Html لأنه لم يكن داخل وسوم PHP بينما الجزء الثاني قد تم إظهاره بواسطة شيفرة PHP. لاحظ أنه يجب إحاطة النص بإشاراتي اقتباس. المتغيرات(variables) تسمح لك بتخزين القيم بدون عرضها. المتغيرات يتم استخدامها بكثرة لتخزين العديد من الأشياء. لنلقي نظرة على مثال بسيط: <?PHP $name = "Daniel"; echo $name; ?> في التعليمات البرمجية السابقة قمت بتخزين قيمة “Daniel” في متغير يدعى name$. بدلاً من إظهار “Daniel” بشكل مباشر، الآن أنا أظهر قيمة name$ مهما كانت. من الوهلة الأولى تبدو لك كزيادة في التعليمات البرمجية بدون فائدة لكن إذا كنا نستعمل هذا المتغير في أكثر من مكان يمكننا تغيير كل شيء بتغيير قيمة هذا المتغير في مكان واحد، بدلاً من تغيير تلك القيم في كل مكان وُضِعت فيه. لاحظ أن الفصل بين أسطر الشيفرات يكون بوضع فاصلة منقوطة (;). إذا أنتجت شيفرتك خطأ فهناك احتمال أنك نسيت وضع فاصلة منقوطة في مكان ما، خطأ شائع ومحبط لكثير من المبرمجين في كل مكان. القيم(values) يمكن أن تكون عدة أنواع. لحد الآن تعرفنا على واحد من هذه الآنواع وهو النوع النصي. النص هو سلسلة من المحارف ويجب إحاطته بإشارتيَ اقتباس (“). نوع آخر وهو النوع الرقمي. الرقم هو أي عدد كامل ولا يجب وضعه ضمن اشارتي اقتباس وإلا سيعتبر نصًا. واحدة من أهم أنواع القيم المصفوفات(array). المصفوفات تخزن عدة قيم، والتي من الممكن أن تكون قيمًا من أنواع مختلفة. <?PHP $name = 'Daniel'; $age = 30; $interests = array( 'guitar', 'singing', 'squash', 'running', 'board games' ); ?> كما ترى يمكن تعريف المصفوفة على الشكل التالي (array(value1 , value2 , value3. يجب كتابة القيم دائمًا في المصفوفة كما تكتب خارج المصفوفة. النص يجب أن يكون محاطًا بإشارتيَ اقتباس (“)، الرقم غير محاط بشيء وهكذا. مثال بسيط إذا بماذا يمكن استخدام ما تعلمناه للآن، ما تعلمناه للآن لا يمكنه إنشاء موقع بعد ولكن حتمًا نحتاج لمثال عملي الآن. لنلقِ نظرة على شيفرة لتطبيق توقعات الطقس: <?PHP $unit = "C"; $temp = 29; if( $unit == 'F' ) { $temp = $temp * 9 / 5 + 32; } $forecast = "The weather today will be great, a Sunny " . $temp . $unit; echo $forecast; ?> هناك بعض الأشياء الجديدة في هذه التعليمات البرمجية، لكن أعتقد أن المثال يشرح نفسه بوضوح. لنراجعه سطرًا بسطر. في البداية، نقوم بإنشاء متغيرين: أول متغير عبارة عن نص يحمل القيمة “C” للمئوية، والمتغير التالي هو عدد صحيح، 29، والذي يهدف إلى تخزين درجة الحرارة الفعلية. الأهداف هنا بسيطة: عرض النص الذي يخبرنا درجة الحرارة الحالية باستخدام القيمة من متغير درجة الحرارة لدينا في وحدة قياس حسب الاختيار، مئوية أو فهرنهايت. السطر التالي هو عبارة if، التي يتم تنفيذ ما بداخلها فقط إذا كانت القيمة داخل الأقواس صحيحة. الشرط هو: $unit == 'F' الذي يترجم منطقيًا كالتالي: إذا كانت قيمة واحدة القياس هي F و هي ليست كذلك و بالتالي سيتم تخطي كتلة هذا الشرط و ما بداخله بدون تنفيذ. في السطر الأخير متغير forecast$ الذي يحوي عبارة “The weather today will be great, a Sunny “ . اعتمادًا على قيمة متغيري unit$ و temp$ ستكون النهاية مختلفة، النقاط بين النصوص والمتغيرات تجمع المتغيرات مع النصوص أو تدمجها. لذا ببساطة سيتم استبدال قيمة temp$ بـ 29 و unit$ بـ C والمخرجات النهائية ستكون: The weather today will be great, a Sunny 29C الآن، ماذا يحدث إذا غيرنا قيمة unit$ إلى F، في البداية سوف يتم تنفيذ التعليمات البرمجية داخل if لأن شرطها تحقق وأصبحت صحيحة، وهذا يعني أن كل شيء بين الأقواس المجعدة سيتم تنفيذه أيضًا. في المثال، اسندت قيمة جديدة لمتغير temp$. أخذت القيمة الأصلية، وتم ضربها في 9، وتقسيمها من على 5 وإضافة 32 وهذه هي المعادلة لتحويل مئوية إلى فهرنهايت. يجب أن تكون القيمة الجديدة لـ temp$ هي 84.2، والقيمة الجديدة unit$ هي F الآن سيتم استبدال المتغيرات بقيمها في الجملة النهائية فتصبح: The weather today will be great, a Sunny 84.2F هذا المثال لا يزال غير مجدٍ بعض الشيء بالنسبة لنا، لكنه يبدأ في إظهار قوة PHP. لاحظ كيف وصلنا إلى الناتج النهائي عن طريق استبدال المتغيرات ببساطة مع القيم. فهو يساعد على الوصول إلى عقلية “replacing placeholder” لأنه هو أساسًا ما تدور حوله لغة PHP. في مثال حقيقي، سنقوم باستخدام القيم الجوية الحالية وبدلًا من كتابة جملة The weather today will be great, a Sunny سوف نستخدم الظروف الفعلية. وقد نرغب أيضًا في التنبؤ غدًا أو في اليوم التالي، مما سيؤدي إلى استبدال “today” بنص آخر. وبالإضافة إلى ذلك، من الواضح أن درجة الحرارة الحالية من الصعب أن تكون مكتوبة يدويًا في الشيفرة البرمجية، فإنه سيكون من الضروري أن يتم استرجاعها من مكان ما. على الرغم من أن هذا يضيف بضع طبقات من التعقيد، لكن المبدأ سيكون نفسه وهو أن نجلب البيانات من مكان ما ونضعها في مخرجاتنا. عبارة if والحلقات الشرطية loops لقد رأينا بالفعل عبارة if في مثال حقيقي. تقوم عبارة if بالتأكد من الشرط داخل الاقواس. إذا كانت النتيجة صحيحة تتم معالجة التعليمات البرمجية داخل الأقواس المجعدة وإلا فأنه لن يتم تنفيذ التعليمات. عبارة if أيضًا ذات صلة مع else if و else. عبارة else if تكتب دائمًا بعد عبارة if. إذا كانت عبارة if غير محققة سيتم التأكد تاليًا إذا كانت عبارة else if محققة، و يمكن أن يكون لدينا عدد غير محدد من عبارات else if بناءً على نفس المنطق. و أخيرًا لدينا عبارة else التي سيتم تنفيذها عندما تكون جميع الشروط التي تسبقها غير محققة، و ليس من الضروري أن يسبق عبارة else عبارة else if يمكنك فقط استعمال عبارة if و else مع بعضهما. لنلقِ نظرة على الأمثلة التالية للتوضيح: // Simple if Statement if( $speed > 50 ) { echo "You are over the speed limit"; } // If and else statement if( $age < 21 ) { echo "You may not buy alcohol"; } else { echo "You may buy alcohol"; } // If, else if and else statement if( $speed < 25 ) { echo "You are too slow"; } elseif( $speed > 120 ) { echo "You are too fast"; } else { echo "Your speed is just right!"; } شيء آخر هنا علينا أن نلاحظه وهو الأسطر التي تبدأ مع مائلة مزدوجة “//”. المائلة المزدوجة تسمح لك بإضافة تعليق سطر واحد في أي مكان في التعليمات البرمجية. يمكنك إضافة تعليقات متعددة الاسطر من خلال البدء مع / * writing whatever you’d like and ending it with * /. الحلقات (loops) تأتي بالعديد من الأشكال والأحجام، أربعة على وجه الدقة. تسمح لك الحلقات بتشغيل نفس التعليمات البرمجية عدة مرات بناءً على استمرار الشرط الذي بدأت به الحلقة. قد تكره الحلقات الآن، لكنها سوف تصبح أقرب حلفائك عندما تصبح أكثر احترافية في كتابة التعليمات البرمجية. لنبدأ مع حلقة foreach. حلقة foreach تمر من كل عناصر المصفوفة وتنفذ تعليمات برمجية معينة. فيما يلي مثال سريع يظهر قائمة Html: <?PHP $names = array( "Daniel Pataki", "Raelene Morey", "James Farmer" ); echo "<ul>"; foreach( $names as $name ) { echo "<li>" . $name . "</li>"; } echo "</ul>"; ?> المفتاح هنا هو فهم العبارة داخل الأقواس، وهي $names as $name، الجزء الأول هو اسم المصفوفة التي ترغب في المرور من خلالها. والثاني هو اسم المتغير الذي يمكن الرجوع إليه من أجل الحصول على قيمة عنصر في هذه المصفوفة الذي تمر عليه حاليًا من خلال الحلقة ولك الحرية في تسمية هذا المتغير أي أنه ليس من الضروري أن تسميه name$ هنا بل يمكن تسميته أي اسم تريده. في مثالنا، سيتم تنفيذ الحلقة ثلاث مرات. عندما تمر الحلقة بالمصفوفة للمرة الأولى ستكون قيمة المتغير name$ هي “Daniel Pataki”، وفي المرة الثانية ستكون “Raelene Morey,” وفي المرة الثالثة ستكون “James Farmer.” يعرض المثال التالي تفاصيل في قائمة، من مصفوفة مترابطة: <?PHP $details = array( "name" => "Daniel Pataki", "Age" => "30", "Twitter" => "http://twitter.com/danielpataki" ); echo "<ul>"; foreach( $details as $label => $value ) { echo "<li><strong>" . $label . "</strong>: " . $value . "</li>"; } echo "</ul>"; ?> الأقواس تحتوي الآن على ثلاثة متغيرات: $details as $label => $value ، ستمر الحلقة الآن من المصفوفة details$. عند كل مرور للحلقة على المصفوفة سيتم مناداة المفتاح label$ والقيمة المرتبطة بهذا المفتاح value$ ، عند المرور الثاني ستكون قيمة label$ هي Age و قيمة value$ هي 30 و ستكون نتيجة تنفيذ التعلمية هي: • Name: Daniel Pataki • Age: 30 • Twitter: http://twitter.com/danielpataki كيف تعمل قوائم مقالات ووردبريس: لنلقِ نظرة الآن على مثال أكثر ارتباطًا بووردبريس: كيف تعمل قوائم مقالات ووردبريس. لا تحاكي التعليمات البرمجية أدناه ووردبريس بالضبط، ولكن جوهر العملية موجود. تخيل أن المنشورات أو المقالات جزء من مصفوفة ارتباطية كبيرة. التعليمات البرمجية الخاصة بصفحتك الرئيسية ببساطة تمر على المصفوفة وتضع البيانات المناسبة في المكان المناسب في بعض وسوم Html: $posts = array( 0 => array( "post_title" => "My First Post", "post_excerpt" => "This is a short snippet of text from the first post", "post_date" => "2015 December 1", "post_author" => "Daniel Pataki" ), 1 => array( "post_title" => "Second Post", "post_excerpt" => "Short exceprt for post number 2", "post_date" => "2015 December 4", "post_author" => "Raelene Morey" ) ); foreach( $posts as $post ) { echo "<div class='post'>"; echo "<h1>" . $post['post_title'] . "</h1>"; echo "<p>" . $post['post_excerpt'] . "</p>"; echo "<div class='post-meta'>Published on " . $post['post_date'] . " by " . $post['post_author'] . "</div>"; echo "</div>"; } الدوال (Functions) بطريقة ما، الدوال تخدم نفس الغرض كما المتغيرات - وسيلة لاستبدال التعليمات البرمجية. يمكن أن تأخذ الدوال كتلة من التعليمات البرمجية وتخزّنها لوقت لاحق وتستخدمها عدة مرات. دعونا ننظر إلى مثال بسيط جدًا باستخدام حلقة المقالات بالمثال السابق. حيث أنه من المحتمل أن يتم استخدام الجزء الذي نظهر فيه عناصر المنشورات في عدة صفحات من موقع الويب - كالصفحة الرئيسية، وصفحات الأرشيف، وصفحات المؤلفين، وما إلى ذلك. سنستخدم نفس التعليمات البرمجية مرارًا وتكرارًا. هذا هو بالضبط الوقت الذي نحتاج فيه إلى الدوال. <?PHP function display_post( $postdata ) { echo "<div class='post'>"; echo "<h1>" . $postdata['post_title'] . "</h1>"; echo "<p>" . $postdata['post_excerpt'] . "</p>"; echo "<div class='post-meta'>Published on " . $postdata['post_date'] . " by " . $postdata['post_author'] . "</div>"; echo "</div>"; } $posts = array( 0 => array( "post_title" => "My First Post", "post_excerpt" => "This is a short snippet of text from the first post", "post_date" => "2015 December 1", "post_author" => "Daniel Pataki" ), 1 => array( "post_title" => "Second Post", "post_excerpt" => "Short exceprt for post number 2", "post_date" => "2015 December 4", "post_author" => "Raelene Morey" ) ); foreach( $posts as $post ) { display_post( $post ); } التعليمة البرمجية أعلاه ليست أقصر، ولكن في أي وقت نريد عرض منشورات في المستقبل يمكننا فقط أن نكتب display_post( $post ); مما يجعلها أكثر كفاءة في المستقبل. كيف يعمل كل هذا؟ دعونا نفهم ذلك من خلال النظر إلى الدالة في الجزء العلوي من التعليمات البرمجية. قمت بتسمية هذه الدالة بـ display_post(); و في القوسين نلاحظ أن هذه الدالة تتوقع وسيط واحد. و نحن نعلم أن هذا الوسيط يجب أن يحتوي معلومات المنشور لذا سيكون هذا الوسيط عبارة عن مصفوفة مترابطة تحتوي معلومات منشور واحد أسميته postdata$. ضمن الأقواس المجعدة ندرج كل التعليمات البرمجية التي نريد تنفيذها عند استدعاء الدالة. هذه هي نفس التعليمات البرمجية التي كانت لدينا من قبل، أنا فقط بحاجة إلى إعادة تسمية كافة المتغيرات إلى postdata$، اسم الوسيط الذي تتوقعه الدالة، والتي يمكننا استخدامها في أي مكان داخل الدالة. في الجزء السفلي من التعليمة البرمجية، يمكنك أن ترى أن عرض المقال الآن أصبح أكثر تنظيمًا للتعليمات البرمجية، لقد استخدمنا للتو display_post($post). أنا متأكد أنك تشعر ببعض الضياع الآن حول التسمية، لماذا استخدمنا post$ في مكان و postdata$ في مكان آخر؟ لنراجع التعليمات البرمجية يتم تشغيل الدوال فقط عندما يتم استدعاؤها، لذا أكثر ما يهمنا في تعليماتنا البرمجية هو مصفوفة $posts، بعد ذلك نقوم بإنشاء الحلقة، كما فعلنا سابقًا. بداخل الحلقة المتغير الذي يحوي بيانات المقال الواحد post$، لحد الآن لم يتغير شيء من مثال الدالة. الآن، بدلًا من وجود كتلة من التعليمات البرمجية هناك نحن ببساطة سنقوم بإسناد هذه التعليمات البرمجية لدالة. نستدعي دالة ()display_post، نعلم أننا نحتاج لتمرير بيانات لهذه الدالة و هذه البيانات هي بيانات مقال واحد. أي متغير يحوي هذه البيانات الآن؟ المتغير post$ ، هذا يأتي من تعريف الحلقة. بعد ذلك، انتقل للأعلى إلى الدالة. سيتم الآن تنفيذها. في هذه الدالة تم تسمية الوسيط postdata$ هذا يعني ببساطة أنه ضمن هذه الدالة سيتم الإشارة إلى البيانات التي يتم تمريرها إلى هذه الدالة كوسيط بـ.postdata$ إنشاء مقتطفات يمكن أن تحتوي الدوال على وسائط متعددة وقيم افتراضية لهذه الوسائط. دعونا ننشئ دالة يمكن أن تحول أي نص إلى مقتطف عن طريق قطعه إلى قطع نصية. نريد دالة لتكون مرنة قدر الإمكان، وقادرة على السيطرة على طول المقتطف، وإلحاق السلسلة إلى النهاية. سنجعل الوسيط الأول النص الذي نريد تقصيره، الوسيط الثاني سيكون لتحديد مقدار المحارف التي نريد اقتطاعها، والثالث النص المُلحق. دعونا نبدأ بإعطاء الدالة إطار للعمل ضمنه: function make_excerpt( $text, $length = 200, $append = '...' ) { } لاحظ أنني أعطيت قيمًا افتراضية لهذه الوسائط. هذا يعني أنه يمكنك استدعاء الدالة دون تمرير الوسيطين الثاني والثالث. إذا قمت بذلك سوف تفترض الدالة أنك تريد إنشاء مقتطف طويل من 200 حرف وإلحاق ثلاث نقاط بعد ذلك. دعونا نكتب محتوى هذه الدالة: function get_excerpt( $text, $length = 200, $append = '...' ) { if( strlen( $text ) < $length ) { return $text; } else { $excerpt = substr( $text, 0, $length ); $excerpt .= $append; return $excerpt; } } لقد أضفت الكثير من الأشياء الجديدة في هذه الدالة، لذلك دعونا نشرح كل إضافة جديدة بالتفصيل. يبدأ كل هذا بعبارة if، الذي تتحقق مما إذا كان النص المعطى أطول من طول معين. وذلك باستخدام دالة مبنية مسبقًا في لغة PHP تدعى ()substr. تأخذ هذه الدالة سلسلة حرفية كوسيط وتعيد طولها. إذا كان طول text$ أقل من length$ يتم إرجاع النص ببساطة - سنتحدث عما يعني الإرجاع خلال لحظات. وإلا، فإننا ننشئ مقتطفًا باستخدام الدالة ()substr. هذه الدالة تقطع سلسلة حرفية وتتطلب ثلاثة وسائط: النص الذي سنقتطع منه، ومن أين تبدأ بالاقتطاع، وطول النص الذي نرد اقتطاعه. نريد أن نبدأ من بداية النص وقطع أحرف length$، وهذا هو السبب لإضافتي رقم 0 كي يقتطع من بداية السلسلة الحرفية. وأخيرًا، نضيف النص الملحق إلى النهاية. لقد استخدمت .= للقيام بذلك. هذه هي نفس كتابة $excerpt = $excerpt. $append في السطر الأخير، قمت بإعادة متغير excerpt$. ما هو الإرجاع؟ حتى الآن كنا في معظم الأحيان نظهر المخرجات، ولكن في كثير من الحالات نحن لا نريد عرض نتيجة حساباتنا. الدالة ()strlen هي مثال جيد على ذلك. أنت لا تريد فعلاً عرض طول متغير text$ أنت ترغب فقط في استخدامه في التعليمات البرمجية لتحقيق شيء ما. ()strlenترجع هذه القيمة، مما يسمح لك باستخدامها في مكان آخر. عند إرجاع قيمة باستخدام دالة، يمكنك إما استخدامها مباشرة مثل دالة ()strlen، أو تعيينها لمتغير $short_text = get_excerpt( $content ) يمكنك بعد ذلك إظهار short_text$ في وقت لاحق عند الحاجة. لمزيد من القراءة والدراسة PHP هي الأساس لجميع قوالب و إضافات WordPress لذلك سوف تحتاج إلى الاعتماد بشكل كبير جدًا على هذه اللغة. عند العمل في بيئة ووردبريس، ستستخدم دوال PHP (مثل strlen و substr)، ولكن هناك أيضًا مئات من الدوال التي تم إنشاؤها خصيصًا لووردبريس من قبل فريق التطوير الأساسي لمساعدتك. ستكتشف بعض هذه الوظائف في الدروس القادمة من هذه السلسلة. لقد غطينا الأساسيات التي تحتاج إلى معرفتها للبدء بتطوير ووردبريس، ولكن الحقيقة هي أننا فقط خدشنا السطح! من المهم أن تقرأ وتستكشف كل المواضيع المتعلقة بووردبرس وPHP لمزيد من العمق والممارسة. ترجمة -وبتصرّف- للمقال WordPress Development for Beginners: Learning PHP لصاحبه Daniel Pataki