מתודה או מאפיין static שייכים למחלקה עצמה ולא לאובייקט כלשהו. קוראים למתודה סטטית עם ClassName::method() וקוראים מאפיין סטטי עם ClassName::$property, בלי ליצור קודם אובייקט. בתוך המחלקה, self:: מתייחס לאותם חברים.
אין new Temperature() בשום מקום. חברים סטטיים שימושיים לפונקציות עזר שלא צריכות מצב של אובייקט (המרות, factories, אימות) ולנתונים ששייכים למחלקה כולה, כמו מונה.
מאפיינים סטטיים משותפים לכל האובייקטים
למאפיין רגיל יש ערך אחד לכל אובייקט. למאפיין סטטי יש ערך אחד לכל המחלקה, ולכן כל אובייקט רואה את אותו ערך. כאן כל User חדש מגדיל מונה משותף ומקבל את המזהה הבא:
שימו לב ל-$ ב-self::$nextId: מאפיינים סטטיים שומרים עליו אחרי ::, בעוד קבועים (self::MAX) לא. מאפיין סטטי חי לבקשת PHP אחת בלבד. באתר טיפוסי (PHP-FPM או Apache) הוא מתחיל מחדש בכל טעינת דף, ולכן הוא לא מקום לשמור נתונים בין מבקרים.
למתודות סטטיות אין $this
מתודה סטטית רצה בלי אובייקט, ולכן $this לא קיים בתוכה. מתודה סטטית יכולה לקרוא למתודות סטטיות אחרות עם self::, אבל היא לא יכולה לקרוא מאפיינים רגילים. גם קריאה סטטית למתודה רגילה נכשלת:
הכיוון ההפוך בסדר: מתודה רגילה יכולה לקרוא למתודות סטטיות, כמו ש-withSeparator() עושה עם self::make().
self מול static: late static binding
self:: מצביע על המחלקה שבה הקוד כתוב. static:: מצביע על המחלקה שעליה המתודה נקראה בזמן ריצה. ההבדל מופיע רק עם ירושה, והוא חשוב במיוחד במתודות factory:
Post::createWithSelf() מחזירה Model, וזה כמעט אף פעם לא מה שהקורא רצה. static מתפרש כ-Post כי זו המחלקה שנכתבה בקריאה; PHP קוראת לזה late static binding. השתמשו ב-static:: וב-new static() במתודות שנועדו לעבור בירושה, וב-self:: כשאתם באמת מתכוונים למחלקה המדויקת הזו. אותו כלל חל על קבועים: static::TABLE לוקח את ה-TABLE של הבת, בעוד self::TABLE תמיד קורא את זה שבמחלקה שבה הקוד כתוב.
מאפיינים סטטיים שעוברים בירושה משותפים
מחלקת בת חולקת את המאפיין הסטטי של האב שלה אלא אם היא מצהירה על משלה. זו ההפתעה הקלאסית של static: שתי מחלקות בת שסופרות לתוך מספר אחד.
ל-Apples אין $count משלה, ולכן Apples::$count הוא Counter::$count, ושניהם מדפיסים 2. Pears מצהירה מחדש על המאפיין וסופרת בעצמה. מאפיין סטטי שמוצהר ב-trait מתנהג אחרת: כל מחלקה שמשתמשת ב-trait מקבלת עותק נפרד.
משתנים סטטיים בתוך פונקציות
ל-static יש משמעות שנייה בתוך גוף של פונקציה: משתנה סטטי שומר על הערך שלו בין קריאות. הערך ההתחלתי מוצב רק בפעם הראשונה שהפונקציה רצה:
ה-slowSquare(12) השני מדלג על החישוב. כמו מאפיינים סטטיים, הערכים האלה מתאפסים בסוף כל בקשה. העמוד משתנים מכסה טווח משתנים באופן כללי.
מתי static הוא הבחירה הלא נכונה
מתודות סטטיות נוחות, וזה הופך אותן לקלות לשימוש יתר. מחלקה שכל המתודות שלה קוראות וכותבות מאפיינים סטטיים היא מצב גלובלי עם שם של מחלקה: כל קורא חולק אותו, בדיקות לא יכולות לקבל עותק נקי, ואי אפשר להחליף למימוש אחר.
שימושים טובים ב-static: פונקציות עזר טהורות בלי מצב (Slug::make()), בנאים עם שם (Color::fromHex()) וקבועים של המחלקה כולה. אם מתודה צריכה נתונים שיכולים להשתנות בין שני שימושים, היא רוצה אובייקט.
שאלות נפוצות
איך קוראים למתודה סטטית ב-PHP?
עם שם המחלקה ו-::: MathHelper::square(4). בתוך אותה מחלקה השתמשו ב-self::square(4) או ב-static::square(4). לא צריך אובייקט, ובתוך מתודה סטטית אין $this.
מה ההבדל בין self ל-static ב-PHP?
self:: תמיד מציין את המחלקה שבה הקוד כתוב. static:: מציין את המחלקה שעליה המתודה נקראה בפועל, שיכולה להיות מחלקת בת; זה נקרא late static binding. לכן במתודה create() של אב, new self() תמיד בונה את האב, בעוד new static() בונה את הבת שקראה לה.
מה זה מאפיין סטטי ב-PHP?
מאפיין שמוצהר public static int $count = 0; שייך למחלקה, ולכן יש ערך אחד שמשותף לכל אובייקט של המחלקה (ולבנות שלה, אלא אם בת מצהירה עליו מחדש). קוראים וכותבים אותו עם ClassName::$count או self::$count; שימו לב ל-$.
אפשר לקרוא למתודה סטטית על אובייקט ב-PHP?
כן. $obj->square(4) ו-$obj::square(4) שתיהן קוראות למתודה הסטטית של המחלקה של האובייקט, אבל עדיין אין בתוכה $this. קריאה למתודה לא סטטית כ-ClassName::method() היא הכיוון שנכשל: מאז PHP 8 היא זורקת Error.
אפשר להשתמש ב-$this במתודה סטטית?
לא. מתודה סטטית רצה בלי אובייקט, ולכן $this לא מוגדר בה ושימוש בו זורק Error ("Using $this when not in object context"). השתמשו ב-self:: או ב-static:: כדי להגיע לחברים סטטיים אחרים.