Menu

enum ב-PHP: backed enums, from(), tryFrom() ו-cases()

enum ב-PHP (8.1 ומעלה) הוא טיפוס עם רשימה קבועה של ערכים: enum Status: string { case Active = 'active'; }. למדו enums טהורים ו-backed, ->value ו-->name, המרה עם from() ו-tryFrom(), רשימת המקרים עם cases(), מתודות, קבועים, ממשקים ו-enums בתוך match.

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

enum ב-PHP (PHP 8.1 ומעלה) מגדיר טיפוס עם קבוצה קבועה של ערכים אפשריים, המקרים שלו: enum Status { case Active; case Banned; }. משתמשים במקרה כ-Status::Active, ופרמטר עם הטיפוס Status לא מקבל שום דבר אחר. backed enum, enum Status: string, נותן גם לכל מקרה ערך שאפשר לשמור ולהמיר בחזרה עם Status::from().

לפני enums, אותו דבר היה רשימה של קבועי מחרוזת, ושום דבר לא מנע משגיאת הקלדה כמו 'actve' להגיע למסד הנתונים. עם Status כטיפוס הפרמטר, אפשר להעביר רק את שלושת המקרים.

enums טהורים ו-backed enums

ב-enum טהור המקרים הם רק שמות. backed enum מצהיר על טיפוס אחרי השם, int או string, ולכל מקרה חייב אז להיות ערך ייחודי מהטיפוס הזה. לכל מקרה יש ->name; רק למקרים של backed יש ->value.

בחרו ב-backed enum בכל פעם שהערך יוצא מהתוכנית: עמודה במסד נתונים, כתובת URL, שדה בטופס, JSON. בחרו ב-enum טהור לערכים שקיימים רק בתוך הקוד, כמו המצב של parser.

המרת ערך עם from() ו-tryFrom()

backed enums מקבלים שתי מתודות סטטיות להפיכת ערך שמור בחזרה למקרה. from() זורקת ValueError לערך לא מוכר; tryFrom() מחזירה null, שמשתלב יפה עם ?? לברירת מחדל:

השתמשו ב-tryFrom() על כל דבר שמשתמש שלח לכם, וב-from() על ערכים שהקוד שלכם כתב, שבהם ערך לא מוכר אומר באג שאתם רוצים לשמוע עליו. הארגומנט עוקב אחרי כללי טיפוס הפרמטר הרגילים: ב-enum של int, Priority::from('5') מחזירה Priority::Normal במצב ברירת המחדל כי '5' מומר קודם ל-5, Priority::from('5x') היא TypeError, ותחת declare(strict_types=1) כל מחרוזת היא TypeError. זה כולל את tryFrom(): Priority::tryFrom('abc') זורקת במקום להחזיר null, אז בדקו קלט מטופס ל-enum של int קודם עם filter_var($raw, FILTER_VALIDATE_INT).

רשימת כל המקרים עם cases()

Enum::cases() מחזירה מערך של כל מקרה, לפי סדר ההצהרה. כך בונים רשימה נפתחת, מאמתים רשימה או מקבלים את כל הערכים עם array_column:

הריצו את זה, בחרו תוכנית ולחצו על Choose: אותו סקריפט ירוץ שוב כש-$_POST['plan'] מלא, ו-tryFrom() הופכת את המחרוזת שנשלחה בחזרה למקרה של Plan. ערך מזויף כמו plan=gold נותן null, ואף אפשרות לא נבחרת.

מתודות, קבועים וממשקים ב-enum

ל-enums יכולות להיות מתודות, מתודות סטטיות וקבועים, והם יכולים לממש ממשקים. בתוך מתודה, $this הוא המקרה הנוכחי, ולכן match ($this) היא הדרך הטבעית לחבר נתונים לכל מקרה. מה שאין ל-enum זה מאפיינים: נתונים לכל מקרה מגיעים ממתודות.

enums בתוך match

match משווה עם ===, ומקרה של enum זהה רק לעצמו, ולכן match ו-enums מתאימים זה לזה. אם שוכחים מקרה והמקרה הזה מגיע ל-match, PHP זורקת UnhandledMatchError במקום להחזיר כלום בשקט:

ראו את match על ההבדלים בין match ל-switch.

enums ב-JSON וכמחרוזות

json_encode() כותבת מקרה של backed enum כערך שלו. enum טהור אי אפשר לקודד, ו-echo של כל מקרה נכשל, כי enum הוא אובייקט, לא מחרוזת. הדפיסו במקום זאת את ->value או את ->name:

echo Role::Admin; זורק Error ("Object of class Role could not be converted to string"), ו-enums לא יכולים לממש __toString(). בדרך חזרה, JSON נותן מחרוזת פשוטה, אז המירו אותה עם from() או tryFrom() כמו שמוצג. עוד על קידוד ב-json_encode.

טעויות נפוצות ב-enums

שלוש שגיאות חוזרות שוב ושוב. מקרה אף פעם לא שווה לערך שלו, מקרה לא יכול להיות מפתח מערך, ו-new לא עובד על enum:

אם אתם צריכים מפה שהמפתחות שלה הם המקרים עצמם, השתמשו ב-SplObjectStorage או ב-WeakMap, שמקבלים אובייקטים כמפתחות.

שאלות נפוצות

איך מקבלים את הערך של enum ב-PHP?

ב-backed enum, קראו את ->value: Status::Active->value הוא 'active'. לכל מקרה יש גם ->name, שם המקרה כמחרוזת ('Active'). ל-enum טהור (בלי : string או : int) יש רק ->name.

מה ההבדל בין from() ל-tryFrom() ב-enums של PHP?

שתיהן הופכות ערך למקרה של backed enum. Status::from('active') מחזירה את המקרה או זורקת ValueError כשלאף מקרה אין את הערך הזה; Status::tryFrom('nope') מחזירה במקום זאת null. השתמשו ב-tryFrom() לקלט משתמש וב-from() כשערך לא תקין הוא באג.

איך מקבלים את כל הערכים של enum ב-PHP?

Status::cases() מחזירה כל מקרה לפי סדר ההצהרה. לערכים של backed enum השתמשו ב-array_column(Status::cases(), 'value'), ולשמות ב-array_column(Status::cases(), 'name').

מה ההבדל בין enum טהור ל-backed enum?

ב-enum טהור (enum Suit { case Hearts; }) המקרים הם רק שמות. backed enum (enum Suit: string { case Hearts = 'H'; }) נותן לכל מקרה ערך int או string ייחודי, שצריך כדי לשמור אותו במסד נתונים, לשים אותו בטופס או ב-JSON, ולהמיר אותו בחזרה עם from() או tryFrom().

האם ל-enum ב-PHP יכולות להיות מתודות?

כן. ל-enums יכולות להיות מתודות, מתודות סטטיות וקבועים, והם יכולים לממש ממשקים. בתוך מתודה, $this הוא המקרה הנוכחי, ולכן return match ($this) { self::Active => 'green', self::Banned => 'red' }; הוא דפוס נפוץ. ל-enums לא יכולים להיות מאפיינים.

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

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

להתחיל