دالتك .. كيف تبنيها وتتعامل معها .. ؟!
الكاتب: sBForum | 13 أغسطس 2006
بسم الله الرحمن الرحيم
يمكننا تعريف الدالة Function بأنها مجموعة أكواد مكتوبة ، لا يتم تنفيذها فوراً .. إنما يمكن استدعاؤها عند الحاجة إليها في برنامجك .. وهناك نوعان للدوال ، إما أن تكون موجودة أصلاً في بنية لغة PHP أو أن ينشئها المستخدم كدوال خاصة به .. ويمكن للدوال تعيين معلومات معينة كي تمرر عبرها ، وعادة تعيد الدالة في نهاية أكوادها قيمة معينة خاصة بها وحسب المعطيات ..
وفي هذا المقال ، سوف نتعرف ان شاء الله على كيفية تعريف الدوال وبناء دوال جديدة خاصة بك .. مهملين القسم الأول من أقسام الدوال المذكورة في التعريف السابق ..
الكثير منا يعلم كيف ينشئ دالة جديدة .. فهنالك وضع افتراضي لذلك وهو سهل أيضاً للكتابة والفهم .. لكن ، علينا أن ندرك بعض الأمور قبل أن نباشر في إنشاء هذه الدوال وإدخالها في برامجنا ... لنبدأ جولتنا هذه مع عالم الدوال الواسع ...
بكل بساطة ، نستخدم تعبير Function لإنشاء دالة خاصة بنا في PHP ..... فبشكل عام ، يكون شكل الكود الذي تكتبه لإنشاء دالتك الخاصة كالتالي:
// هنا الأوامر التي ستكون داخل دالتك
}
نضع التعبير function ثم نتبعه باسم الدالة التي نريد إنشاءها .. ثم نتبعهم بأسماء العوامل Arguments التي نريد تمريرها للدالة عند استعمالها .. يمكن الاستغناء عن هذه العوامل أيضاً حيث أن الدالة لن تطلب ولن تسمح بتمرير عوامل لها عند استخدامها مستقبلاً بعد انشائها ..
تكون اسماء العوامل على شكل أسماء متغيرات عادية variables .. لنأخذ مثال على دالة ننشئها ولها عامل واحد ..
print (" <H1>". $word ."</H1>");
}
BigWord ( "هذه الكلمة ستبدو كبيرة !" );
قمنا هنا بإنشاء دالة تقوم بطباعة وسم <H1> الذي سيظهر الكلمات المطبوعة بخط كبير للعناوين الرئيسية ثم طبعنا العامل الذي مررناه عبر الدالة بعد الوسم ثم أغلقنا الوسم بهذا </h1> ...
ثم قمنا باستدعاء الدالة عن طريق كتابة اسمها فوراً .. ثم فتح أقواس وكتابة الكلمات التي نريد طباعتها بالتنسيق السابق عن طريق هذه الدالة ...
لنأخذ الآن مثال على كيفية إنشاء الدالة دون عوامل نهائياً ..
هنا قمنا بإنشاء دالة تقوم بطباعة كلمة "ملاحظة:" باللون الأحمر .. دون تمرير أي متغير [ عامل ] لها .. وذلك باستدعائها بشكل عادي بكتابة اسمها ثم فتح قوس وإغلاقه فوراً دون وضع أي شيء بين القوسين ...
الآن ، سنتعرف إلى كيفية وضع عامل بقيمة افتراضية ، بحيث إذا لم يتم تمرير قيمة معينة في ذلك العامل سيتم اعتماد القيمة الافتراضية ولن يتم طباعة خطأ في عدد العوامل الممررة .. ومثال ذلك :
هذا هو أحد الأمثلة السابق ذكرها .. لكن تعديلنا عليه هو إضافة القيمة الافتراضية للعامل word .. فقد قمنا بوضع علامة المساواة ( = ) بعد اسم العامل ، ثم قمنا بفتح علامة التنصيص المفردة [ أو المزدوجة ] ثم نضع القيمة الافتراضية للعامل ، وهي هنا قيمة فارغة ، ثم نغلق علامة التنصيص بنفس شكل علامة التنصيص الأولى ... في هذا المثال ، يمكن تمرير قيمة للدالة عبر العامل نفسه ، ويمكن تجاهل تمرير قيمة كما هو واضح في أمر استدعاء الدالة .. لم نقم بوضع قيمة للعامل .. وبذلك لن يتم طباعة أي شيء .. لأن القيمة الافتراضية هي لاشيء .. إلا أنه ايضاً لن يتم طباعة رسالة خطأ لأن هناك قيمة افتراضية تسمح بعدم تمرير قيمة لنفس العامل ..
نريد الآن أن نتعرف إلى كيفية اعادة قيمة معينة في الدالة التي نقوم بإنشائها ..
يمكن إعادة قيمة معينة في جزء من الدالة باستخدام التعبير return .. هذا التعبير يقوم بإيقاف تنفيذ الدالة [ أي انه لن يقوم بتنفيذ الأكواد التي تليه ] ويقوم بإعادة قيمة Value أو كائن Object ... والمثال التالي سيوضح العملية بشكل أكبر :
$retval = $firstnum + $secondnum;
return $retval;
}
print addNums(4,3);
// سوف يكون الناتج المطبوع يساوي 7
ماذا لو استغنينا عن المتغير المؤقت $retval .. يمكننا إعادة قيمة معينة فوراً دون تخزينها في متغير .. فقط نضع تعبير return ومن ثم نلحقه بالقيمة التي نريد إرجاعها في ناتج الدالة ، وهنا القيمة هي عبارة عن مجموع الرقم الأول مع الرقم الثاني .. لنستغني في هذا المثال عن المتغير المؤقت ونشاهد كيفية إعادة قيمة مباشرة ...
return ( $firstnum + $secondnum );
}
print addNums(4,3);
// سوف يكون الناتج المطبوع يساوي 7
جملة return يمكن أن تعد قيمة ، أو كائن ، أو حتى لا شيء على الإطلاق ... وذلك لإنهاء العمليات ..
فمثلاًً ، يمكن أن تكون القيمة عبارة عن عدد أو رقم مباشر ، مثل :
أو عبارة عن قيمة نصية ، مثل :
أو ناتج لعملية حسابية ، مثل :
أو حتى ناتج دالة أخرى ، مثل :
الاستدعاء النشط [ الديناميكي ] لدالة :
يمكننا تعيين اسم دالة في متغير نصي String لاستدعائها في برنامجنا .. تماماً باسم الدالة التي نستدعيها به عند الحاجة إليها .. في المثال التالي محض توضيح لهذه الفكرة :
في هذا المثال ، قمنا بتعريف متغير جديد اسمه $function_name .. ثم قمنا بتحديد قيمة نصية له تساوي sayHello .. ثم قمنا باستدعاء الدالة التي اسمها موجود في المتغير $function_name عن طريق هذا السطر :
فهذا السطر في هذا المثال مساو لهذا الأمر:
لماذا علينا استخدام هذه الخاصية ؟؟ .... ربما يترأود هذا التساؤل في بالك .. يمكن استخدام هذه الطريقة في جلب بيانات معينة من مصفوفة $_GET مثلاًً وتنفيذ دوالها .. سنفرض أن لدينا متغير خارجي نرسله عن طريق عنوان الصفحة بفرض أن اسمه type وهناك احتمال أن قيمته ستكون 1 أو 2 .. ولدينا دالتان .. أحدها ستنفذ الطريقة الأولى والأخرى الثانية ..
أي أننا سنقوم بتنفيذ الكود التالي في ذلك الملف .. :
echo " هذه هي الطريقة الأولى ";
}
function type2 () {
echo " هذه هي الطريقة الثانية ";
}
function default_type () {
echo " هذه هي الطريقة الافتراضية ";
}
if ( !isset($_GET["type"]) ) $_GET["type"] = ""; // نقوم بتعريف المتغير الخارجي ان لم يكن معرف من قبل
$type = (int) $_GET["type"]; // هنا نقوم بتحويل قيمة المتغير الخارجي إلى عدد صحيح لعدم سماح تمرير حروف آخرى
if ( $type == 1 or $type == 2 ) { // نتأكد من ان قيمة المتغير الخارجي هي 1 أو 2
$function_name = "type". $type; // نحدد اسم الدالة التي نريد تنفيذها
} else { // إذا لم يكن المتغير الخارجي يساوي 1 أو 2
$function_name = "default_type"; // نقوم بتنفيذ دالة آخرى لنعتبرها الدالة الافتراضية
}
$function_name(); // نقوم باستدعاء الدالة عن طريق اسمها المخزن في المتغير المحدد
في هذا المثال .. نقوم باستدعاء الملف من المتصفح كالتالي:
http://localhost/test.php?type=1
مع افتراض ان الملف على المزود localhost .. واسمه test.php ..
اذا قمنا باستدعائه بالشكل السابق فإنه سيقوم بطلب وتنفيذ الدالة المسماة type1 .. اما إذا قمنا بتغيير الرقم 1 إلى الرقم 2 [ وهو قيمة المتغير الخارجي type ] فإنه سيتم طلب وتنفيذ الدالة المسماة type2 .. وأي قيمة خلاف ذلك سواء كانت أكبر أو أصغر أو ليست قيمة عددية فإنه سيتم طلب وتنفيذ الدالة الأخيرة المسماة default_type .......
بعض الأمور المتعلقة باستخدام المتغيرات في بناء الدوال الجديدة :
المتغيرات التي يتم تعريفها داخل دالة تبقى خاصة بتلك الدالة ، أي أنه لا يمكن استخدامها خارجها .. سواء في الكود العادي أو داخل دوال أخرى .. وهذا الأمر يساعد بشكل جيد في تحسين أداء البرامج الكبيرة وضمان عملها ، حيث يمنع تغيير محتويات المتغيرات المستخدمة في كل دالة إذا تم استخدام نفس الاسم لمتغيرين أو أكثر ..
لنأخذ مثال لنتأكد من أن المتغيرات داخل دالة لا تعمل خارجها :
في المثال السابق ، لاحظ أنه عند تنفيذ الكود لن يتم طباعة أي شيء في المتصفح ، حيث أن المتغير الداخلي المحلي $forTest لا يمكن أن يعمل خارج الدالة ... لاحظ أن محاولة الوصول إلى متغير غير موجود [ غير معرف مسبقاً ] لا ينتج عنه رسالة خطأ .. بل يصدر فقط رسالة ملاحظة Notice للتنبيه بذلك ، وفي العادة هذا النوع من الرسائل يكون معطل من قبل خيارات PHP في ملف php.ini .. حتى لا يزعج المستخدم لأن الكثير من الناس يقعون في مثل هذا الخطأ ...
خارج إطار الموضوع : يمكن منع عرض تلك الرسالة [ حل المشكلة ] باستخدام جملة شرطية للتأكد من وجود هذا المتغير .. لاحظ الكود السابق بعد التعديل :
دالة isset تقوم بالتأكد من وجود المتغير أو تعريفه قبل استخدامه .....
بنفس النهج ، فإن المتغيرات المعرفة خارج الدالة لا يمكن استخدامها داخلها ... هذا في الوضع الطبيعي طبعاًً ..
لكن ، ماذا لو احتجنا إلى استخدام هذه المتغيرات في داخل دالة ما ننشئها .. ؟ ماذا سنفعل عندها ؟
لنجري أولاًً تجربة لمحاول استخدام متغير خارجي في دالة ...
لاحظ في هذا المثال سيطبع على الشاشة : " رقمي هو : " دون طباعة العدد الموجود في المتغير $myNum الخارجي ، حيث أن الوصول إليه ممنوع في تلك الدالة ..
طبعاًً سترافق هذه العملية ملاحظة Notice مفادها أن المتغير غير معرف ، ونصها مشابه لما يلي :
Notice: Undefined variable: myNum in xxx on line xxx
إذا بحثنا في تراكيب وتعابير لغة PHP ... سنجد تعبير يدعى Global .. هذا سيساعدنا بشكل كبير في تضمين المتغيرات الخارجية في دوالنا الخاصة عند بنائها ..
الآن سنضيف عبارة global قبل طباعة المتغير ونلحقها باسم المتغير الذي نريد جلبه إلى داخل دالتنا .. لاحظ أنه علينا إعادة العملية لكل متغير ، أو يمكنك فصل أسماء المتغيرات بعد تعبير global بفاصلة عادية .. المثال السابق بعد إدخال global :
في هذا المثال ، تمت عملية طباعة المتغير الخارجي داخل الدالة بنجاح ، وذلك تبعاً لتضمين المتغير بواسطة تعبير global ..
.... لكن ، كن حذراً .. إذا قمت بتغيير محتوى المتغير في داخل دالة [ بعد أن تقوم قد ضمنت المتغير بواسطة global ] ، فإن قيمته الأصلية ستتغير .. أي أن قيمته خارج تلك الدالة ستتغير إلى القيمة الجديدة ، لأن المتغير الذي قمنا بتضمينه ليس نسخة عن المتغير القديم ، وإنما هو نفسه .. أما في العوامل التي نمررها للدالة، فإنه يتم أخذ نسخة إضافية منها ويصبح التحكم بها بعيداً عن المتغيرات الأصلية ...
حفظ المتغيرات بين طلبات الدالة بتعبير Static :
في هذه المرحلة ، لدينا فكرة علينا تنفيذها ، وهي أن ننشئ دالة تحتوي على متغير بداخلها ، بحيث أن على هذه الدالة تذكر قيمة هذا المتغير في كل مرة يتم تنفيذ الدالة فيها .. لنفرض أن قيمة المتغير كانت في أول حالة تنفيذ تساوي 5 فعلى الدالة نفسها في المرة القادمة أن تتذكر أن المتغير هذا له القيمة 5 ، وإذا تم تغييره يجب أن تتذكر القيمة الجديدة وتستخدمها في المرات القادمة بدلاً من القديمة ..
فكر قليلاً .. ماذا ستستخدم لهذا الغرض ؟؟؟! ربما كانت إجابتك هي أن تستخدم تعبير Global .. دعنا إذاً نجرب المهمة مع Global ... وذلك في المثال التالي :
قمنا في بداية هذا المثال بتعريف المتغير $num وإعطائه القيمة 0 ... ثم قمنا بإنشاء دالة باسم myHeadline تحتاج لعامل واحد اسمه $headline ومحتواه عبارة عن قيمة نصية بعنوان الخبر .. ثم قمنا باستخدام تعبير global لتمرير المتغير $num ضمن هذه الدالة .. بعدها ، قمنا بإضافة واحد إلى قيمة المتغير $num .. ففي أول مرة تصبح قيمته تساوي 1 .. الآن، قمنا بطباعة عنوان الخبر بتنسيق كبير مسبوقاً برقم الخبر المخزن في المتغير $num .. في أول تنفيذ للدالة كما ذكرت ستصبح قيمة المتغير $num تساوي 1 .. وهذه القيمة تبقى مخزنة في المتغير الأصلي $num .. ففي المرة الثانية ، تكون نفس القيمة في المتغير ويتم إضافة واحد عليها ، فتصبح 2 .. وهكذا عند كل استدعاء جديد للدالة ..
لكن ، عند قراءة قيمة المتغير $num في كل مرة يتم تنفيذ الدالة فيها ، سيتم جلب المتغير الأصلي من خارج الدالة ، ثم تمريره إلى داخل الدالة وقراءته .. وهذا ما قد يجعل التعبير global غير مناسب تماماً لهذه العملية .. كما أنه يقوم بتغيير قيمة المتغير الأصلي خارج الدالة ..
وهذا ما يمكن ان نعتبر به التعبير Static مفيداً .. حيث أنه عندما يتم تعريف متغير معين واستخدامه من قبل هذا التعبير ، فإن ذاك المتغير سيبقى محلياً وخاصاً بتلك الدالة التي تم استدعاؤه فيها .. وفي نفس الوقت ، ستتذكر الدالة نفسها آخر قيمة للمتغير في كل عملية استدعاء لتلك الدالة .. لنأخذ نفس المثال السابق مع استخدام Static بدلاً من Global ..
قد يبدو عند تنفيذ هذا الكود أنه مشابه تماماً للكود باستخدام global ، إلا أن استخدام static سيساعد بدرجة كبيرة في جودة البرنامج وضمان سلامة سيره وخاصة في البرامج أو المشاريع الكبيرة نوعاً ما ... الآن يمكننا نسخ دالة myHeadline ولصقها في أي سكربت أو برنامج آخرى دون القلق على المتغيرات الخارجية ، حتى لو تشابهت اسماؤها مع المتغيرات الداخلية .. بهذا ، نكون قد جعلنا الكود الذي كتبناه أكثر حداثة ومناسبة للاحداث ..
نتوقف عند هذا الحد في هذا الدرس ، ربما أعود للتحدث في هذا الموضوع في مقالات أخرى لاحقاً .. والسلام عليكم ورحمة الله وبركاته
تم بحمد الله تعالى.