الدالة المجهولة، وتُسمى أيضًا الدالة المغلقة، دالة بلا اسم. تكتب function ($param) { ... } حيث تُتوقع قيمة: أسندها إلى متغير، أو مرّرها إلى دالة أخرى، أو أعِدها. ويمكنها حمل متغيرات من الشيفرة المحيطة بـ use ($var).
كل دالة مجهولة كائن من الصنف المدمج Closure، ولهذا يمكن تخزينها وتمريرها واستدعاؤها لاحقًا بـ $greet(...).
الكلمة use تلتقط بالقيمة
لا تستطيع الدالة المغلقة رؤية المتغيرات الخارجية بنفسها. تنسخ use ($x) قيمة $x إلى الدالة المغلقة لحظة إنشائها، لا لحظة تنفيذها:
use بالمرجع: &$var
تعطي use (&$x) الدالة المغلقة المتغير نفسه لا نسخة منه. التغييرات داخل الدالة المغلقة مرئية في الخارج، والتغييرات في الخارج تُرى داخلها. وهكذا تضيف دالة استدعاء إلى مجموع أو تحتفظ بعداد.
كل استدعاء لـ makeCounter() ينشئ $count جديدًا، وتُبقيه الدالة المغلقة المعادة حيًا بعد انتهاء الدالة. وهذا ما تشير إليه كلمة «مغلقة»: تنغلق الدالة على المتغيرات التي تحتاجها.
تمرير دالة مغلقة دالةَ استدعاء
تأخذ دوال مثل array_map() وarray_filter() وusort() وarray_walk() دالة وسيطًا. وتتيح لك الدالة المغلقة كتابتها في مكانها، بعدد الجمل الذي تحتاجه المهمة:
عندما يكون الجسم تعبيرًا واحدًا، تكون الدالة السهمية مثل fn($p) => $p['price'] أقصر ولا تحتاج إلى use.
القابلات للاستدعاء: أسماء الدوال والتوابع وstrlen(...)
يقبل المعامل ذو النوع callable أكثر من الدوال المغلقة. فالنص الذي فيه اسم دالة، والمصفوفة التي فيها كائن واسم تابع، والمصفوفة التي فيها اسم صنف واسم تابع ساكن، كلها تُحسب. ومنذ PHP 8.1، تحوّل صيغة الاستدعاء من الدرجة الأولى strlen(...) أيًّا منها إلى Closure مباشرة.
تُفحص صيغة (...) عند تنفيذ السطر: الخطأ الإملائي يرمي Error في مكانه. أما نص مثل 'strtoupr' فليس إلا نصًا حتى يحاول أحدهم استدعاءه.
الدوال المغلقة داخل صنف: $this وstatic
الدالة المغلقة المنشأة داخل تابع تُربط بها $this تلقائيًا، فتستطيع استخدام خصائص الكائن. علّمها بـ static function عندما لا تحتاج إلى $this، وهذا يمنعها أيضًا من إبقاء الكائن حيًا.
نسيان use
أشهر أخطاء الدوال المغلقة استخدام متغير خارجي دون ذكره في use. داخل الدالة المغلقة لا يوجد المتغير:
$minAge = 18;
$adults = array_filter($people, function ($p) {
return $p['age'] >= $minAge; // $minAge is not in use (...)
});
PHP prints: Warning: Undefined variable $minAge
تكون $minAge داخلها null، وأي عمر يُقارن بـ >= null يعطي true، فيجتاز كل شخص التصفية. وعلى خادم يخفي التحذيرات، لا شيء يخبرك. أضف المتغير إلى use:
الأسئلة الشائعة
ما هي الدالة المغلقة في PHP؟
دالة دون اسم، تُنشأ بـ function (...) { ... } وتُخزَّن في متغير أو تُمرَّر وسيطًا. تمثلها PHP بكائن من الصنف Closure. ويمكنها حمل متغيرات من النطاق الذي أُنشئت فيه، مذكورة في use (...).
ماذا تفعل الكلمة use في الدالة المغلقة في PHP؟
تنسخ use ($x) المتغير الخارجي $x إلى الدالة المغلقة عند إنشائها. ولا تُرى التغييرات اللاحقة على $x في الخارج. اكتب use (&$x) لمشاركة المتغير بدلًا من ذلك، فتسري التغييرات في الاتجاهين.
ما هو القابل للاستدعاء (callable) في PHP؟
أي شيء تستطيع PHP استدعاءه: دالة مغلقة، أو اسم دالة نصًا ('strtoupper')، أو مصفوفة [$object, 'method'] أو [ClassName::class, 'staticMethod']، أو كائن فيه __invoke(). استخدم النوع callable لقبول أي منها وis_callable() للفحص.
ماذا تعني strlen(...) في PHP؟
هي صيغة الاستدعاء من الدرجة الأولى منذ PHP 8.1: تنشئ strlen(...) كائن Closure من الدالة دون استدعائها. وتعمل أيضًا مع التوابع، $obj->method(...)، والتوابع الساكنة، Foo::bar(...)، وتُفحص عند تنفيذ السطر، على عكس الاسم النصي.
هل أحتاج إلى فاصلة منقوطة بعد الدالة المجهولة؟
نعم، عندما تُسندها: $f = function () { ... }; جملة إسناد، لذا تنتهي بـ ;. وحذفها خطأ في التحليل. أما الدالة المغلقة الممررة مباشرة وسيطًا فلا تحتاج إلى فاصلة منقوطة خاصة بها.