קלט/פלט · זרימת בקרה

die#

זריקת חריגה.

die זורק חריגה הבנויה מ־LIST. אם החריגה מתרחשת בתוך eval, ה־eval מסתיים עם undef ו־$@ מחזיק את ערך החריגה. אם דבר אינו תופס אותה, Perl מדפיס את ההודעה ל־STDERR והמפרש יוצא עם סטטוס שונה מאפס. החריגה יכולה להיות מחרוזת פשוטה, רשימה שמומרת למחרוזת, או הפניה - בדרך כלל עצם מבורך הנושא מצב שגיאה מובנה.

תקציר#

die LIST
die $message
die $exception_object
die                         # re-raise / propagate current $@

מה מוחזר#

die אינו חוזר. השליטה מועברת ל־eval הדינמי המקיף הקרוב ביותר (שמחזיר אז undef בהקשר סקלרי או רשימה ריקה בהקשר רשימה), או - אם אין eval מקיף - המפרש משחרר את המחסנית, מריץ את מטפלי END ו־DESTROY, ויוצא.

ערך החריגה עצמו נוחת ב־$@:

  • חריגות מחרוזת - ההודעה המומרת למחרוזת, כולל כל at FILE line N.\n שצורף (ראו להלן).

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

ביציאה לא־תפוסה, קוד היציאה נגזר מ־$! ומ־$?:

exit $! if $!;              # errno
exit $? >> 8 if $? >> 8;    # child exit status
exit 255;                   # last resort

יש להסתמך רק על כך שקוד היציאה שונה מאפס; הערך המדויק הוא קידוד במאמץ־מירבי של כל מצב שגיאה גלובלי שהיה פעיל ברגע הזריקה.

מצב גלובלי שהוא נוגע בו#

  • $@ - נכתב עם החריגה בשחרור המחסנית אל eval, נקרא על־ידי הצורה חסרת־הארגומנטים של die כדי להפיץ חריגה קיימת, ונקרא על־ידי מדפיס חריגות לא־תפוסות.

  • $! - נקרא בעת גזירת קוד יציאה עבור חריגה לא־תפוסה, ובדרך כלל משובץ בתוך ההודעה עצמה (die "open $f: $!").

  • $? - נקרא בעת גזירת קוד יציאה אם $! הוא אפס. מטפלי END ו־DESTROY עדיין יכולים לשנות אותו לפני שהתהליך בפועל יוצא.

  • $. - מספר שורת הקלט הנוכחית, מצורף לחריגות מחרוזת שחסר להן תו שורה חדשה מסיים.

  • $SIG{__DIE__} - אם מוגדר, המטפל רץ לפני שהחריגה מופצת, עם החריגה כארגומנט שלו. המטפל יכול להחליף את החריגה על־ידי קריאה ל־die שוב עם ערך שונה.

  • $^S - קריא על־ידי מטפלי $SIG{__DIE__} כדי לדעת האם ה־die מתרחש בתוך eval.

כלל תו השורה החדשה המסיים#

האם die מצרף מידע מיקום תלוי בתו אחד בסוף ההודעה:

  • ההודעה מסתיימת ב־"\n" - בשימוש מילולי. דבר אינו מצורף. יש להשתמש בצורה זו כאשר ההודעה היא כבר אבחנה שלמה הפונה למשתמש.

  • ההודעה אינה מסתיימת ב־"\n" - Perl מצרף " at FILE line N", ואם נקרא קובץ, ", <HANDLE> line M", ואז "." מסיים ותו שורה חדשה. יש להשתמש בצורה זו במהלך פיתוח, או בכל פעם שאיתור קריאת ה־die במקור שימושי יותר מהודעה מסודרת.

die "bad config\n";                 # "bad config\n"
die "bad config";                   # "bad config at script.pl line 42.\n"

אידיום נפוץ הוא לצרף ", stopped" כדי לגרום לסיומת המיקום להיקרא באופן טבעי:

die "/etc/games is no good, stopped";
# /etc/games is no good, stopped at canasta line 123.

לחריגות הפניה לעולם לא מצורף מידע מיקום - המרת עצם למחרוזת כדי לבחון אותו תסכל את התכלית של זריקת עצם. אם רוצים קובץ ושורה בתוך חריגה מובנית, יש ללכוד אותם בזמן הבנייה (__FILE__, __LINE__, או caller).

חריגות בעלות ערך־הפניה#

העברת הפניה - בדרך כלל עצם מבורך - מאפשרת ל־$@ לשאת מצב מובנה במקום מחרוזת שיש לפרסר אותה אחר־כך:

package MyApp::Error;
sub new   { my ($c, %a) = @_; bless { %a }, $c }
sub code  { $_[0]{code}  }
sub where { $_[0]{where} }

eval {
    die MyApp::Error->new(code => 'EPARSE', where => 'line 12');
};
if (my $err = $@) {
    if (ref($err) && $err->isa('MyApp::Error')) {
        warn "parse error at ", $err->where;
    }
    else {
        die $err;   # not ours - re-raise
    }
}

יש להעמיס את ההמרה למחרוזת על מחלקות החריגה כך שחריגה לא־תפוסה עדיין מדפיסה הודעה שימושית:

use overload '""' => sub { "[MyApp::Error ".$_[0]->code."]\n" };

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

מכיוון ש־$@ גלובלי, יש להעתיק אותו למשתנה לקסיקלי לפני בחינתו - כל קריאת מתודה, ref, או isa שמופעלים במהלך הטיפול יכולים בעצמם להפעיל eval פנימי ולדרוס את $@:

if (my $err = $@) { ... }       # safe
if ($@) { $@->method; ... }     # unsafe: method may reset $@

הפצה: die ללא ארגומנט (או מחרוזת ריקה)#

כאשר LIST ריקה או מומרת למחרוזת "", die אינו זורק חריגה חדשה - הוא זורק מחדש כל מה שנמצא ב־$@:

  • אם $@ מחזיק מחרוזת, die מצרף "\t...propagated at FILE line N.\n" וזורק מחדש. זוהי הדרך הקנונית לתת לחריגה להמשיך במעלה מחסנית הקריאות לאחר בדיקת התאמה חלקית:

    eval { risky() };
    die unless $@ =~ /Expected exception/;
    
  • אם $@ מחזיק הפניית עצם עם מתודה PROPAGATE, המתודה הזו נקראת כ־$@ = eval { $@->PROPAGATE(__FILE__, __LINE__) }, והערך המוחזר מחליף את $@ לפני הזריקה מחדש. יש לממש PROPAGATE על מחלקת חריגה כאשר רוצים שהחריגה תתעד את שרשרת הזריקות מחדש.

  • אם $@ מחזיק הפניית עצם ללא PROPAGATE, ההפניה נזרקת מחדש ללא שינוי.

  • אם גם $@ ריק, המחרוזת "Died" בשימוש.

הוו של $SIG{__DIE__}#

קביעת $SIG{__DIE__} מתקינה מטפל שרץ כאשר die נורה, עם החריגה כארגומנט שלו. המטפל יכול לבחון או להחליף את החריגה על־ידי קריאה ל־die שוב עם ערך שונה. הוא רץ גם בתוך eval, וזו הסיבה הרגילה לרצות אותו מהדרך:

local $SIG{__DIE__} = sub {
    die @_ if $^S;              # inside eval: do nothing special
    log_fatal(@_);              # outside eval: log before we exit
};

$^S הוא undef במהלך הידור, אמת בתוך eval, ושקר ברמה העליונה - יש להשתמש בו כדי לשעֵר עבודת מטפל שמשמעותית רק עבור חריגות לא־תפוסות.

דוגמאות#

יציאה מהירה עם הודעה נקייה (שימו לב שתו השורה החדשה המסיים מדכא את צירוף הקובץ/שורה):

chdir '/var/spool' or die "can't cd to spool: $!\n";

die ללא תו שורה חדשה במהלך פיתוח כך שהמיקום מצורף:

die "unexpected empty record";
# unexpected empty record at parse.pl line 87.

תפיסת חריגת מחרוזת:

eval {
    parse($input);
};
if ($@) {
    warn "parse failed: $@";    # $@ already ends in "\n" if the
                                # die'd message did
}

זריקה ותפיסה של עצם חריגה מבורך:

eval {
    die MyApp::Error->new(code => 'EIO', detail => $!);
};
if (my $err = $@) {
    if (ref($err) && $err->isa('MyApp::Error')) {
        handle($err);
    }
    else {
        die $err;               # re-raise anything unexpected
    }
}

הפצה מותנית - לתפוס מחלקה אחת, לתת לשאר לעבור:

eval { work() };
die unless $@ =~ /^recoverable:/;
recover();

מקרי קצה#

  • רשימה עם שני פריטים או יותר מומרת למחרוזת ומשורשרת לכדי ההודעה: die "read failed on ", $file, ": $!". כלל תו השורה החדשה חל על התוצאה המשורשרת.

  • רשימה ריקה (die; או die "";) מפעילה את מסלול ההפצה המתואר לעיל, לא חריגה חדשה.

  • הפניה עם תו שורה חדשה מסיים בתוך הצורה המומרת למחרוזת אינה רלוונטית: מיקום לעולם לא מצורף להפניה, ללא קשר למה שההעמסה "" שלה מפיקה.

  • die בתוך DESTROY במהלך השמדה גלובלית עדיין יכול לירות את $SIG{__DIE__} אך עלול לא להתפשט כצפוי - המפרש כבר משחרר את המחסנית. יש לשמור על הורסים מתגוננים.

  • die לא־תפוס במהלך בלוק END מריץ את שאר בלוקי END אך קובע סטטוס יציאה לפי כלל $!/$? לעיל.

  • eval מקונן ו־$SIG{__DIE__}: המטפל רץ עבור כל die, כולל אלו הנתפסים על־ידי eval פנימי. יש להגן עם $^S אם למטפל יש תופעות לוואי.

  • זריקה מחדש של $@ הנוכחי: עדיף die; חשוף על־פני die $@;. הצורה החשופה מפעילה את מנגנון ההפצה (סיומת ...propagated, הוו PROPAGATE); die $@ לא - הוא מתייחס ל־$@ כערך חריגה חדש.

הבדלים מהמעלה־הזרם#

תאימות מלאה עם Perl 5.42 מהמעלה־הזרם.

ראו גם#

  • eval - המבנה היחיד שתופס die; צורת הבלוק שלו לוכדת חריגות אל $@

  • warn - אותם כללי פורמט (תו שורה חדשה מסיים מדכא את המיקום), אך כותב ל־STDERR ואינו משחרר את המחסנית

  • caller - לכידת קובץ ושורה בזמן הזריקה בעת בניית עצם חריגה מובנה

  • exit - לשימוש כאשר רוצים קוד יציאה מסוים ללא מנגנון טיפול החריגות

  • $@ - היכן שהחריגה נוחתת לאחר ש־eval תופס אותה, והמקור ש־die חסר־הארגומנט זורק מחדש ממנו

  • $SIG{__DIE__} - הוו טרום־זריקה שיכול לבחון או לשכתב את החריגה

  • $^S - אומר למטפל $SIG{__DIE__} האם הוא רץ בתוך eval