Menu

פונקציות אנונימיות ו-closures ב-PHP: מילת המפתח use

פונקציה אנונימית (closure) היא פונקציה בלי שם שנשמרת במשתנה: $greet = function ($name) { return "Hi $name"; };. למדו את מילת המפתח use, לכידה לפי הפניה, callables, תחביר ה-first-class callable strlen(...) ו-closures בתוך מחלקות.

בדף הזה יש עורכים שאפשר להריץ - לערוך, להריץ ולראות את הפלט מיד.

פונקציה אנונימית, שנקראת גם closure, היא פונקציה בלי שם. כותבים function ($param) { ... } במקום שבו מצופה ערך: מציבים אותה במשתנה, מעבירים אותה לפונקציה אחרת או מחזירים אותה. היא יכולה לשאת משתנים מהקוד שמסביב עם use ($var).

כל פונקציה אנונימית היא אובייקט של המחלקה המובנית Closure, ולכן אפשר לשמור אותה, להעביר אותה הלאה ולקרוא לה מאוחר יותר עם $greet(...).

מילת המפתח use לוכדת לפי ערך

closure לא יכול לראות משתנים חיצוניים בעצמו. use ($x) מעתיקה את הערך של $x לתוך ה-closure ברגע שה-closure נוצר, לא כשהוא רץ:

use לפי הפניה: &$var

use (&$x) נותנת ל-closure את המשתנה עצמו ולא עותק. שינויים בתוך ה-closure נראים בחוץ, ושינויים בחוץ נראים בפנים. כך callback מוסיף לסכום או מחזיק מונה.

כל קריאה ל-makeCounter() יוצרת $count חדש, וה-closure שמוחזר שומר אותו בחיים אחרי שהפונקציה חזרה. לזה מתייחס המונח "closure": הפונקציה סוגרת על המשתנים שהיא צריכה.

העברת closure כ-callback

פונקציות כמו array_map(), array_filter(), usort() ו-array_walk() מקבלות פונקציה כארגומנט. closure מאפשר לכתוב אותה במקום, עם כמה פקודות שהעבודה צריכה:

כשהגוף הוא ביטוי יחיד, פונקציית חץ כמו fn($p) => $p['price'] קצרה יותר ולא צריכה use.

callables: שמות פונקציות, מתודות ו-strlen(...)

פרמטר עם הטיפוס callable מקבל יותר מ-closures. מחרוזת עם שם פונקציה, מערך עם אובייקט ושם מתודה, ומערך עם שם מחלקה ושם מתודה סטטית כולם נחשבים. מאז PHP 8.1, תחביר ה-first-class callable strlen(...) הופך כל אחד מהם ל-Closure ישירות.

הצורה (...) נבדקת כשהשורה רצה: שגיאת הקלדה זורקת Error בדיוק שם. מחרוזת כמו 'strtoupr' היא רק מחרוזת עד שמישהו מנסה לקרוא לה.

closures בתוך מחלקה: $this ו-static

ל-closure שנוצר בתוך מתודה יש $this מקושר אוטומטית, כך שהוא יכול להשתמש במאפיינים של האובייקט. סמנו אותו כ-static function כשהוא לא צריך את $this, וזה גם מונע ממנו להשאיר את האובייקט בחיים.

שכחת use

הבאג הנפוץ ביותר ב-closures הוא שימוש במשתנה חיצוני בלי לרשום אותו ב-use. בתוך ה-closure המשתנה לא קיים:

$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:

שאלות נפוצות

מה זה closure ב-PHP?

פונקציה בלי שם, שנוצרת עם function (...) { ... } ונשמרת במשתנה או מועברת כארגומנט. PHP מייצגת אותה כאובייקט של המחלקה Closure. היא יכולה לשאת משתנים מהטווח שבו היא נוצרה, שרשומים ב-use (...).

מה מילת המפתח use עושה ב-closure של PHP?

use ($x) מעתיקה את המשתנה החיצוני $x לתוך ה-closure כשה-closure נוצר. שינויים מאוחרים ב-$x בחוץ לא נראים. כתבו use (&$x) כדי לשתף את המשתנה במקום זאת, כך ששינויים עוברים לשני הכיוונים.

מה זה callable ב-PHP?

כל דבר ש-PHP יכולה לקרוא לו: closure, שם של פונקציה כמחרוזת ('strtoupper'), מערך [$object, 'method'] או [ClassName::class, 'staticMethod'], או אובייקט עם __invoke(). השתמשו בטיפוס callable כדי לקבל כל אחד מהם וב-is_callable() כדי לבדוק.

מה המשמעות של strlen(...) ב-PHP?

זה תחביר ה-first-class callable מ-PHP 8.1: strlen(...) יוצר Closure מהפונקציה בלי לקרוא לה. הוא עובד גם למתודות, $obj->method(...), ולמתודות סטטיות, Foo::bar(...), ונבדק כשהשורה רצה, בניגוד לשם במחרוזת.

צריך נקודה פסיק אחרי פונקציה אנונימית?

כן, כשמציבים אותה: $f = function () { ... }; היא פקודת הצבה, ולכן היא מסתיימת ב-;. השמטה שלה היא שגיאת תחביר. closure שמועבר ישירות כארגומנט לא צריך נקודה פסיק משלו.

איור של שפות התכנות ב-Coddy

ללמוד תכנות עם Coddy

להתחיל