מחלקות ותכנות מונחה־עצמים

isa#

בדיקה האם עצם הוא מופע של מחלקה או של תת־מחלקה כלשהי הנגזרת ממנה.

isa הוא אופרטור בינארי, לא פונקציה. האופרנד השמאלי הוא ביטוי שאמור להפיק הפניה לעצם; האופרנד הימני מנקב מחלקה. הוא מחזיר אמת כאשר האופרנד השמאלי הוא הפניה blessed שמחלקתה - או יורשת מ־ - המחלקה משמאל. הוא מחזיר שקר עבור כל דבר אחר, כולל undef, הפניות שאינן blessed, ומחרוזות פשוטות. הוא לעולם אינו זורק חריגה.

בניגוד למתודה הישנה UNIVERSAL::isa, isa בטוח ליישום על ערכים שרירותיים: קריאת $x->isa("Foo") על מחרוזת פשוטה שבמקרה מנקבת מחלקה ($x = "Foo") מפעילה את מתודת המחלקה ומחזירה אמת, וזה כמעט אף פעם לא מה שהקורא התכוון. isa כאופרטור מדווח אמת רק עבור מופעים blessed.

תקציר#

use feature 'isa';          # or: use v5.36;

$obj isa Some::Class
$obj isa "Different::Class"
$obj isa $name_of_class

מה מקבלים בחזרה#

1 עבור עצם blessed שמחלקתו היא, או נגזרת מ־, CLASS. המחרוזת הריקה המוגדרת "" (ערך שקרי שהוא מספרית אפס ופטור מאזהרות uninitialized) בכל מקרה אחר.

האופרטור לעולם אינו מעלה חריגה: ערכים לא־מוגדרים, ערכים שאינם הפניות, וערכים בעלי תיוג שגוי פשוט נכשלים בבדיקה.

שער התכונה#

isa זמין מ־Perl 5.31.6 והפך לבלתי־ניסיוני ב־Perl 5.36. זוהי תכונה לקסיקלית, מופעלת על־ידי אחת מאלה:

use feature 'isa';
use v5.36;                  # enables the 5.36 feature bundle

תחת no feature 'isa' (או בתחום שמעולם לא הפעיל אותה), ה־bareword isa חוזר להיות מזהה רגיל, והביטוי הוא שגיאת תחביר.

הצד הימני#

האופרנד הימני של isa נפתר לשם מחלקה בזמן הידור כאשר הוא bareword:

$obj isa Some::Class        # bareword - resolved at compile time

כל ביטוי אחר מוערך בזמן ריצה וחייב להפיק מחרוזת המנקבת את המחלקה:

$obj isa "Different::Class" # string literal
$obj isa $class_name        # scalar variable
$obj isa (ref $other)       # any expression yielding a string

Barewords בצד ימין אינם צריכים להיות מוצהרים, מיובאים או נטענים; isa מתייעץ רק בטבלת הסמלים של CLASS כדי לעבור על @ISA. מחלקה שמעולם לא נטענה פשוט אין לה הורים, לכן $obj isa Unknown::Class פשוט נכשל בבדיקה.

דוגמאות#

בדיקת מופע בסיסית:

use feature 'isa';

package Animal { }
package Dog    { our @ISA = ('Animal'); }

my $rex = bless {}, 'Dog';

$rex isa Dog;               # true
$rex isa Animal;            # true - via @ISA
$rex isa Cat;               # false

התנייה של קריאת מתודה במחלקה בפועל:

sub describe {
    my ($thing) = @_;
    return "unknown" unless $thing isa Animal;
    return $thing->sound;
}

בטוח על ערכים שרירותיים - ללא חריגה על ערכים שאינם הפניות:

undef      isa Animal;      # false
"Animal"   isa Animal;      # false - a string is not an instance
[]         isa Animal;      # false - unblessed ref
{}         isa Animal;      # false - unblessed ref
\&main::x  isa Animal;      # false - unblessed code ref

דיספאץ« על שם מחלקה שנלכד בזמן ריצה:

for my $class (qw(Dog Cat Fish)) {
    if ($rex isa $class) {
        say "rex is a $class";
    }
}

מדוע isa עדיף על UNIVERSAL::isa כמתודה:

my $x = "Dog";
$x->isa('Dog');             # TRUE - string "Dog" is treated as a class name
$x isa Dog;                 # false - $x is not a blessed instance

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

מקרי קצה#

  • האופרנד השמאלי הוא undef: האופרטור מחזיר שקר. אזהרת uninitialized אינה נפלטת - זוהי בדיקה שקטה במכוון.

  • האופרנד השמאלי הוא הפניה שאינה blessed: שקר. isa דורש הפניה blessed; הפניות למערך, הפניות להאש, והפניות לקוד שמעולם לא עברו דרך bless נכשלות בבדיקה.

  • האופרנד השמאלי הוא מחרוזת פשוטה: שקר, גם כאשר המחרוזת תואמת שם מחלקה טעון. זוהי ההפרדה ההתנהגותית מ־UNIVERSAL::isa הנקרא כמתודה.

  • האופרנד הימני מנקב מחלקה לא־ידועה: האופרטור אינו טוען אוטומטית או דורש את המודול. הוא עובר על ה־@ISA של המחלקה; למחלקה לא־ידועה אין @ISA, לכן הבדיקה נכשלת.

  • ירושה מרובה: isa מכבד את כל סדר פתרון מתודות הפעיל במחלקה (mro, c3 או חיפוש ברירת המחדל לעומק־ראשון). החיפוש הוא אותה סריקה שבה דיספאץ« המתודה משתמש.

  • עצמים שעברו rebless: הבדיקה משקפת את ה־blessing הנוכחי. קריאה נוספת ל־bless על הפניה משנה את מה ש־isa מדווח.

  • קדימות הפרסר: isa הוא אופרטור בעל שם לא־אסוציאטיבי באותה קדימות כמו האופרטורים היחסיים (lt, gt, le, ge). שרשור ($a isa B isa C) הוא שגיאת תחביר, כמו עם שאר האופרטורים היחסיים.

  • התכונה אינה מופעלת: ללא use feature 'isa' (או use v5.36), הפרסר רואה את isa כ־bareword רגיל והביטוי אינו מצליח להידור.

  • האופרנד הימני כקריאה לתת־שגרה: יש לכתוב אותו בסוגריים. $obj isa some_class() מתפרסר; $obj isa some_class מתייחס ל־some_class כשם המחלקה המילולי (bareword).

הבדלים מ־upstream#

תואם מלא ל־upstream Perl 5.42.

ראו גם#

  • bless - לצרף שם מחלקה להפניה כדי של־isa (ולדיספאץ« המתודות) יהיה מה לדווח

  • ref - לאחזר את שם המחלקה של הפניה blessed, או את הטיפוס שבבסיס עבור כאלה שאינן blessed; משלים את isa כאשר נדרש השם ולא תשובת כן/לא

  • class - תחביר הצהרת המחלקה המקורי (תכונה class, Perl 5.38+); עצמים שנבנו עם class הם הפניות blessed רגילות ועובדים עם isa ללא שינוי

  • UNIVERSAL::isa - צורת המתודה ההיסטורית. עובדת על כל הפניה, אך גם מחזירה אמת עבור מחרוזות פשוטות שבמקרה מנקבות מחלקה; יש להשתמש באופרטור בקוד חדש

  • mro - שולט בסדר פתרון המתודות ש־isa עובר באמצעותו על @ISA

  • perlop - טבלת קדימות האופרטורים המלאה; isa ממוקם עם האופרטורים היחסיים הלא־אסוציאטיביים