php 101 الدوال (Functions) في PHP


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

عندما نكتب برنامجًا طويلًا جدًا، فإن الشيفرة ستوزَّع في عددٍ من الملفات والأصناف (classes) والدوال (functions)؛ الدوال هي مجموعة من التعليمات التي تنجز مُهمِّة معيّنة وهدفها ألا تكرر الشيفرات التي تكتبها؛ فمثلًا في نظام للاستيثاق، يكون هنالك دوال لتسجيل الدخول (login) والتسجيل (register) وتسجيل الخروج (logout).

functions-in-php.png.72ed56e8dd3aad246c6

أبسط أشكال الدوال

إن الشكل العام لأبسط دالة هو:

<?php
function function_name()
{
  // الشيفرة
}
?>

وكما في المتغيرات، تستطيع إسناد أي اسم إلى الدالة (أعطينا الدالة في المثال السابق الاسم function_name). تُكتَب الشيفرة التي ستنفذها الدالة عندما يتم استدعاؤها بين أقواس معقوفة ({})؛ نستطيع استدعاء الدالة عبر كتابة اسمها ويليه أقواس عادية () كما في المثال الآتي:

<?php

// يمكنك أن تستدعي الدالة هنا قبل تعريفها

// تعريف دالة ذات الاسم say_hello
function say_hello()
{
  // كل ما تفعله هذه الدالة هو طباعة hello
  echo "hello";
}

// استدعاء الدالة
say_hello();
?>

الدوال ذات الوسائط

يمكننا تمرير المعلومات الإضافية (مثل اسم المستخدم وكلمة المرور) إلى الدوال باستخدام الوسائط (arguments)، وعلينا تعريف المعاملات (parameters). 

ملاحظة: الوسائط هي البيانات التي نمررها إلى الدالة عندما نستدعيها، أما المعاملات فهي المتغيرات التي نُعرِّفها عندما نكتب الشيفرة الخاصة بالدالة.

يمكننا أن نعتبر أن المعاملات هي حاويات والوسائط هي البيانات التي نضعها في تلك الحاويات.

<?php

// دالة تسجيل الدخول ذات وسيطين
function login($user, $pass)
{
  // تطبع هذه الدالة اسم المستخدم وكلمة المرور
  echo "hello, username is $user and password is $pass";
}

// استدعاء الدالة
login("user1","UsEr!p@$$W0rD");

// استدعاء الدالة مرةً أخرى
login("user2","simplepassword");
?>

المعاملات ذوات القيم الافتراضية

يمكننا أن نعطي قيمًا افتراضية للمعاملات لكي يمكن تجاوز تحديد قيمتها عند استدعاء الدالة.

<?php

// دالة تسجيل الدخول ذات ثلاثة وسائط
function login($user, $pass, $active = "not active")
{
  // تعرِض هذه الدالة اسم المستخدم وكلمة مروره وحالته
  echo "hello, username is $user and password is $pass and user is $active";
}

// استدعاء الدالة
login('user1','UsEr!p@$$W0rD');

// استدعاء الدالة مرةً أخرى
login('user2','simplepassword', 'active');
?>

ملاحظة: إن أردت ألّا تُحدِّد قيمةً لوسيطٍ ما عند استدعاء الدالة، فيجب أن يكون المعامل الموافق لذاك الوسيط في آخر القائمة كما في المثال السابق. ويملك المعامل افتراضيًا القيمة "null".

الدوال ذات المعاملات متغيرة العدد

يمكن أن تملك الدوال عددًا متغيرًا من المعاملات؛ وفي الواقع، تستطيع تمرير إي عدد من الوسائط إلى دالة؛ استعمل الدوال المُضمَّنة في PHP الآتية للوصول إلى تلك الوسائط: 

  • الدالة func_get_args()‎: تُعيد مصفوفة بجميع الوسائط المُمرَّرة 
  • الدالة func_num_args()‎: تُعيد العدد الإجمالي للوسائط المُمرَّرة.
  • الدالة func_get_arg(argument_number)‎: تُعيد المتغير ذو الرقم argument_number 

سنظهِر -في المثال الآتي- مجموع الأرقام المُمرَّرة إلى الدالة كوسائط بالإضافة إلى عرضها.

<?php

function sum()
{
  // سنستعمل func_get_args() للحصول على كل المعاملات على شكل مصفوفة
  $ary = func_get_args();
  print_r($ary);
  echo "<br>";

  $sum = 0;
  // سنستعمل func_num_args للحصول على العدد الكلي للمعاملات
  for($i = 0; $i < func_num_args(); $i++)
  {
    // سنستعمل func_get_arg(index) للحصول على قيمة معامل معيّن
    echo func_get_arg($i).'<br>';
    $sum+= func_get_arg($i);
  }
  echo "sum is $sum <br><br>";
}

sum(1,2,3,4);
sum(23,2343,54,2,1,6);
?>

ناتج تنفيذ السكربت السابق هو:

Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 4 ) 
1
2
3
4
sum is 10 

Array ( [0] => 23 [1] => 2343 [2] => 54 [3] => 2 [4] => 1 [5] => 6 ) 
23
2343
54
2
1
6
sum is 2429

إعادة القيم من الدوال

لاحظ أننا في المثال السابق طبعنا السلسلة النصية مباشرةً، لكن ماذا لو أردنا أن نجعل الدالة تُعيد قيمةً ما؟ نستعمل العبارة البرمجية return لإعادة قيمة من الدالة، وتُسبِّب هذه العبارة بإنهاء تنفيذ الدالة مباشرةً وإعادة القيمة إلى مكان استدعاء الدالة، لنرى مثالًا عن دالة تُعيد مربَّع العدد المُمرَّر إليها:

<?php
function square ($num) {
  return $num * $num;
}

// الناتج هو 16
echo square (4);
?>

لاحظ أنك لا تستطيع إعادة أكثر من قيمة من الدالة، لكن يمكنك إعادة مصفوفة التي تؤدي نفس الدور تقريبًا.

<?php
function powers ($num) {
  return array ($num, $num * $num, $num * $num * $num);
}

// الناتج هو: Array ( [0] => 4 [1] => 16 [2] => 64 )
print_r(powers (4));
?>

مجالات تعريف الدوال

تستطيع أن تستدعي الدوال المُعرَّفة في الأمثلة السابقة قبل مكان تعريفها، لأن مجالها (scope) هو المجال العام، يجدر بالذكر أنَّك تستطيع تعريف الدوال داخل جملة شرطية (if) لكن لا يمكنك استدعاؤها إن لم يتحقق الشرط كما في المثال الآتي:

<?php
$str = 'create the function';
global_function();

// لا يمكننا استدعاء الدالة not_global هاهنا، لأن المفسر لا يعتبرها موجودةً إن لم تتحقق الجملة الشرطية الآتية
if ($str == 'create the function') {
  function not_global() {
    echo 'I don\'t exist until program execution reaches me';
  }
}

// نستطيع الآن استدعاء الدالة not_global بعد اختبار أن السلسلة $str مساوية للقيمة اعلاه، لتجنب إظهار خطأ
if ($str == 'create the function') not_global();

function global_function() {
  echo 'I exist immediately upon program start';
}
?>

الأمر سيان لآلية تعريف دالة داخل دالة أخرى:

<?php
function global_function() {
  function not_global() {
    echo 'I don\'t exist until global_function() is called';
  }
}

// لا يمكننا استدعاء not_global هنا، إذ علينا استدعاء global_function أولًا
global_function();

// نستطيع الآن استدعاء الدالة not_global، لأن استدعاء global_function قد جعلها متاحةً للمفسر
not_global();
?>

المتغيرات في الدوال

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

<?php
// المتغير $a في المجال العام
$a = 1;

function test() {
  echo $a; // لا يمكن الوصول إلى المتغير $a لأنه في المجال العام
}

// لن يظهر أي شيء ﻷن المتغير $a ليس ضمن مجال الدالة
test();

// سيظهر الرقم 1، لأن المجال هو العام
echo $a;
?>

لن تظهر مخرجات عند استدعاء الدالة test()‎ لأن الدالة echo داخلها تُشير إلى نسخة محلية من المتغير ‎$a التي لم تُسنَد لها قيمة في ذاك المجال. يمكن الوصول إلى المتغيرات في المجال العام من داخل الدوال باستخدام الكلمة المحجوزة global كما يلي:

<?php

$a = 1;
$b = 2;

function sum (){
  // أصبح بإمكاننا الوصول إلى المتغيرين في مجال الدالة الخاص، وتعديل قيمتهما مباشرةً
  global $a,  $b;
  $b = $a  + $b;
}

sum();
echo $b;
?>

نوعٌ أخيرٌ هو المتغيرات الثابتة (static variables) التي يُسمَح بوجودها في مجال الدوال الخاص فقط، لكنها لا تفقد قيمتها عند انتهاء تنفيذ الدالة، انظر إلى المثال الآتي لتوضيح الأمور:

<?php
function test() {
  $a = 0;
  echo $a;
  $a++;
}
?>

الدالة السابقة عديمة الفائدة لأنها في كل مرة تُستدعى فيها ستضبط قيمة المتغير ‎$a إلى 0، ثم ستُظهِر قيمة ذاك المتغير (التي هي صفر)، وأخيرًا لن نستفيد من زيادة قيمة المتغير (‎$a++‎) لانتهاء تنفيذ الدالة ولن يعود المتغير ‎$a موجودًا. أما لو عرَّفنا المتغير ‎$a على أنه ثابت، فلن يفقد قيمته بعد انتهاء تنفيذ الدالة:

<?php
function test() {
  static $a = 0;
  echo $a;
  $a++;
}
?>

ستتم تهيئة المتغير ‎$a في أول مرة تُستدعى فيها الدالة، وستُطبَع قيمة المتغير وستزداد قيمته في كل مرة تستدعى فيها الدالة مرةً أخرى.

<?php

function test() {
  static $a = 0;
  echo $a;
  $a++;
}

//الناتج 0
test();

//الناتج 1
test();

//الناتج 2
test();
?>

ملاحظة: يجب إسناد قيم بسيطة إلى المتغيرات الثابتة عند تعريفها، إذ لا يجوز استعمال التعابير الرياضية أو إسناد القيم المُعادة من الدوال 
إليها.

المعاملات المرجعية

رأينا كيف أنَّ جميع الدوال السابقة تعيد قيمة ما بناءً على العمليات التي تُجرى فيها، لكنها لا تستطيع تعديل قيم الوسائط المُمرَّرة إليها، لكن "التمرير بالمرجعية" (pass by reference) يسمح للدوال بتعديل قيم الوسائط مباشرةً، لنأخذ مثالًا بسيطًا يوضِّح هذا الأمر:

<?php

function test(&$var) {
  $var++;
  // لاحظ عدم استعمال عبارة return هنا
}

$a = 5;
test($a);
echo $a; // الناتج هو 6
?>

الاختلاف الوحيد الذي يجعل الوسائط تُمرَّر بمرجعيتها هو وضع محرف «&» قبل اسم الوسيط عند تعريف الدالة.

الدوال المجهولة

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

<?php

$square = function ($num) {
  echo $num * $num;
};

$square(2); // الناتج 4
$square(15); // الناتج 225
?>

نستطيع أن نُمرِّر إلى الدوال المجهولة أي متغير موجود في مجال المتغيرات الأعلى منها وذلك باستخدام الكلمة المحجوزة use، تأمّل في المثال الآتي وفي تعليقاته:

<?php
$message = 'hello';

// لم نستعمل الكلمة المفتاحية use هنا
$example = function () {
    echo $message;
};
$example(); // لن تَظهَر أيّة قيمة (أو بالتحديد، سيظهر خطأ Notice ﻷن المتغير غير مُعرَّف)

// تمرير المتغير $message
$example = function () use ($message) {
    echo $message;
};
$example(); // الناتج: hello

// القيمة المُمرّرة تؤخذ قبل تعريف الدالة، وليس قبل استدعائها
$message = 'world';
$example(); // الناتج: hello

// إعادة قيمة المتغير إلى قيمته الأصلية
$message = 'hello';

// الوراثة بالمرجعية (inherit by-reference)
$example = function () use (&$message) {
    echo $message;
};
$example(); // الناتج: hello

// إذا تغيرت قيمة المتغير الآن، فستتأثر الدالة المجهولة بها
$message = 'world';
$example(); // الناتج: world

// استعمال الوسائط العادية
$example = function ($arg) use ($message) {
    echo $arg . ' ' . $message;
};
$example("hello"); // الناتج: hello world
?>

تمرين

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

المصادر



1 شخص أعجب بهذا


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


درسك هدية بالنسبة لي  والله انت معلم شكرا لك على المعلومة المفيدة و الجيدة شكرا لك على هذه المعلومات القيمة.. مجهود رائع حقيقة أعجبني موضوعك وأشكركم على المشاركة معنا مع أطيب التحيات واصل.

2 اشخاص أعجبوا بهذا

شارك هذا التعليق


رابط هذا التعليق
شارك على الشبكات الإجتماعية


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

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

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


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

تسجيل الدخول

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


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