Menu

traits ב-PHP: use, כמה traits ו-insteadof

trait ב-PHP הוא בלוק של מתודות ומאפיינים לשימוש חוזר שמעתיקים לתוך מחלקה עם use TraitName;. למדו שימוש בכמה traits, פתרון התנגשויות שמות עם insteadof ו-as, חברים מופשטים וסטטיים ב-trait, איזו מתודה מנצחת, ו-trait מול ממשק מול מחלקה מופשטת.

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

trait ב-PHP הוא בלוק של מתודות ומאפיינים לשימוש חוזר. מצהירים עליו עם trait Name { ... } ומושכים אותו לכל מחלקה עם use Name; בתוך גוף המחלקה. PHP מעתיקה את החברים של ה-trait לתוך המחלקה, ולכן הם עובדים בדיוק כאילו כתבתם אותם שם.

ל-User ול-Robot אין אב משותף, ובכל זאת לשתיהן יש עכשיו hello(). traits קיימים בשביל המקרה הזה: מחלקות ב-PHP יכולות להרחיב רק מחלקה אחת, ו-trait משתף קוד הצידה, בין מחלקות שאינן קשורות.

traits עם מאפיינים

trait יכול להביא מאפיינים יחד עם המתודות שלו. המתודות משתמשות ב-$this כמו כל מתודה של המחלקה, כי ברגע שה-trait מועתק פנימה, הן מתודות של המחלקה:

מחלקה לא יכולה להצהיר על מאפיין עם אותו שם כמו מאפיין של trait אלא אם שתי ההצהרות זהות (אותה רמת גישה, טיפוס וערך ברירת מחדל); אחרת זו שגיאה קטלנית.

שימוש בכמה traits

רשמו כמה traits בפקודת use אחת, מופרדים בפסיקים, או כתבו כמה שורות use. המחלקה מקבלת את החברים של כולם:

פתרון התנגשויות עם insteadof ו-as

כששני traits מגדירים מתודה עם אותו שם, PHP מסרבת לנחש ונעצרת עם שגיאה קטלנית. בתוך בלוק use, insteadof בוחרת את המנצח, ו-as שומרת את המתודה המפסידה תחת שם אחר:

עם use EnglishGreeting, FrenchGreeting; פשוט ובלי בלוק, הסקריפט נעצר לפני שמשהו מודפס:

PHP Fatal error:  Trait method FrenchGreeting::greet has not been applied as Host::greet, because of collision with EnglishGreeting::greet in /home/index.php on line 12

as יכולה גם לשנות רמת גישה. use Loggable { log as protected; } הופכת את log() של ה-trait למוגנת רק במחלקה הזו, ו-use Loggable { log as private writeLog; } מוסיפה כינוי פרטי.

חברים מופשטים וסטטיים ב-trait

trait יכול לדרוש משהו מהמחלקה שמשתמשת בו על ידי הצהרה על מתודה מופשטת. יכולים להיות לו גם מתודות סטטיות ומאפיינים סטטיים. כל מחלקה שמשתמשת ב-trait מקבלת עותק משלה של מאפיין סטטי:

Car ו-Bike סופרות בנפרד, כי המאפיין הסטטי מועתק לכל מחלקה. זה שונה ממאפיין סטטי שמוצהר במחלקת אב משותפת, שכל הבנות חולקות; העמוד static מראה את המקרה הזה.

איזו מתודה מנצחת: מחלקה, trait או אב

אם אותו שם מתודה קיים במחלקה עצמה, ב-trait שהיא משתמשת בו ובמחלקת האב שלה, PHP בוחרת בסדר הזה: המתודה של המחלקה עצמה, אחר כך של ה-trait, אחר כך של האב. בתוך ה-trait, parent:: עדיין מגיע לגרסה של האב:

trait אינו טיפוס

instanceof אף פעם לא מתאים ל-trait, ופרמטר עם טיפוס של שם trait דוחה כל אובייקט עם TypeError. כדי לשאול "האם למחלקה הזו יש את ההתנהגות", חברו את ה-trait לממשק, או בדקו את המחלקה עם class_uses():

הדפוס שלמעלה הוא הרגיל: הממשק Exportable הוא מה שפונקציות משתמשות בו כרמז טיפוס ומה ש-instanceof בודק, וה-trait ExportsProperties הוא מימוש מוכן שמחלקות יכולות להשתמש בו או להחליף אותו. trait לבדו הוא קוד משותף בלי חוזה; כשאתם שמים לב שאתם בודקים class_uses() בלוגיקה העסקית, ה-trait רצה ממשק לצידו. לקוד שמשותף למשפחה של מחלקות קשורות, מחלקה מופשטת עשויה להיות הבחירה הפשוטה יותר.

שאלות נפוצות

מה זה trait ב-PHP?

trait הוא קבוצה עם שם של מתודות (ומאפיינים) שמוצהרת עם trait Name { } ומחלקה מושכת אותה פנימה עם use Name;. PHP מעתיקה את החברים של ה-trait לתוך המחלקה, ולכן הם מתנהגים כאילו כתבתם אותם שם. זו דרך לשתף קוד בין מחלקות שאין להן אב משותף.

האם מחלקה ב-PHP יכולה להשתמש בכמה traits?

כן: use Timestamps, SoftDeletes; או כמה שורות use. אם שני traits מגדירים מתודה עם אותו שם, חייבים לבחור אחת עם insteadof, למשל use A, B { A::hello insteadof B; }, ואפשר לשמור את השנייה תחת שם חדש עם B::hello as helloB;.

מה ההבדל בין trait לממשק ב-PHP?

ממשק הוא טיפוס בלי קוד: הוא אומר אילו מתודות חייבות להיות למחלקה, ו-instanceof עובד איתו. trait הוא קוד בלי טיפוס: הוא מדביק גופי מתודות לתוך מחלקה, אבל $obj instanceof SomeTrait הוא תמיד false. לעיתים קרובות משלבים אותם: ממשק בשביל הטיפוס, trait עם מימוש ברירת מחדל.

האם ל-trait יכול להיות בנאי או מתודות מופשטות?

כן לשניהם. trait יכול להצהיר abstract public function name(): string; כדי לדרוש מהמחלקה שמשתמשת בו לספק את המתודה הזו, והוא יכול להגדיר __construct, אם כי בנאי ב-trait מתנגש בקלות עם הבנאי של המחלקה עצמה ולעיתים רחוקות הוא רעיון טוב.

איזו מתודה מנצחת אם מחלקה ו-trait מגדירים את אותה מתודה?

המתודה של המחלקה עצמה מנצחת את זו של ה-trait, והמתודה של ה-trait מנצחת מתודה שעברה בירושה ממחלקת האב. אז הסדר הוא: המחלקה, אחר כך ה-trait, אחר כך האב.

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

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

להתחיל