קלט/פלט

warn#

מנפיק אזהרה ל־STDERR.

warn הופך את LIST למחרוזת ומדפיס את התוצאה ל־STDERR - אותו מנגנון עיצוב כמו die, פחות השחרור. הבקרה חוזרת לקורא; דבר אינו נזרק, דבר אינו נתפס. יש לפנות אליו כאשר התוכנית צריכה להמשיך לרוץ אבל המשתמש, המפעיל, או הלוג ראויים לשמוע על משהו לא צפוי.

תקציר#

warn LIST
warn $message
warn                         # re-surface current $@ as a warning

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

warn מחזיר 1 בנסיבות רגילות. ערך ההחזרה כמעט אף פעם אינו שימושי - נקודת הקריאה היא תופעת הלוואי על STDERR (או על מה ש־$SIG{__WARN__} עושה עם ההודעה).

שלא כמו die, warn אינו משחרר. הביצוע ממשיך עם המשפט אחרי הקריאה.

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

  • $@ - נקרא על ידי הצורה ללא ארגומנט. אם $@ מחזיק ערך לא־ריק, warn מחזיר אותו לפני השטח (ראו התפשטות להלן). warn אינו כותב את $@.

  • $,, $\ - אינם נועצים. warn אינו print; מפרידי הפלט ומפריד הרשומות אינם משחקים תפקיד. ההודעה נכתבת כמחרוזת יחידה.

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

  • $SIG{__WARN__} - אם מוגדר, המטפל רץ במקום כתיבה ל־STDERR. ראו הוו של $SIG{__WARN__} להלן.

  • STDERR - היעד בברירת מחדל. כל הפניה מחדש של STDERR (2> ברמת shell, open STDERR, ..., שכבת PerlIO) משפיעה על איפה פלט warn נוחת.

חוק השורה החדשה הגוררת#

אותו כלל כמו die חל, ומאותה סיבה:

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

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

warn "cache is stale\n";            # "cache is stale\n"
warn "cache is stale";              # "cache is stale at main.pl line 42.\n"

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

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

כאשר LIST ריק או הופך למחרוזת "", warn אינו מנפיק הודעה רעננה - הוא מחזיר לפני השטח את מה שיש ב־$@:

  • אם $@ לא־ריק, warn מצרף לו "\t...caught" ומנפיק את התוצאה. זוהי הדרך הקנונית להבחין שחריגה נתפסה מבלי לאפשר לה למות בשקט:

    eval { risky() };
    warn if $@;                     # "<whatever died>\n\t...caught at ..."
    
  • אם $@ גם ריק, המחרוזת "Warning: Something's wrong" בשימוש.

זה חוסר סימטריה בכוונה עם die: die ללא ארגומנט זורק מחדש (מפעיל את מנגנון ההתפשטות ואת הוו PROPAGATE עבור עצמים); warn ללא ארגומנט מדווח על מה שכבר ב־$@.

הוו $SIG{__WARN__}#

הגדרת $SIG{__WARN__} מתקינה מטפל הרץ במקום הכתיבה לברירת מחדל ל־STDERR. המטפל מקבל את החריגה הנגזרת מ־LIST כארגומנט יחיד והוא אחראי לסילוקה - רישומה ב־log, כתיבה מחדש שלה, הסלמה שלה ל־die, או הפלתה לרצפה:

local $SIG{__WARN__} = sub {
    my ($msg) = @_;
    return if $msg =~ /^Use of uninitialized/;  # silently drop
    log_warning($msg);
};

שלוש חוסרי־סימטריה עם $SIG{__DIE__} שכדאי להפנים:

  • ההודעה בברירת מחדל מדוכאת. $SIG{__DIE__} רץ לצד מנגנון החריגה; $SIG{__WARN__} רץ במקום הכתיבה ל־STDERR בברירת מחדל. אם המטפל לא עושה דבר, האזהרה מופלת בשקט.

  • כדי להעביר את האזהרה דרך, יש לקרוא ל־warn שוב. המטפל אינו נכנס מחדש לקריאת warn שלו, כך שאין לולאה אינסופית:

    local $SIG{__WARN__} = sub {
        log_warning($_[0]);
        warn $_[0];                  # re-emit to STDERR as well
    };
    
  • מטפל __WARN__ יכול להשתיק אזהרות חובה - אזהרות ש־no warnings אינו יכול לכבות. זה הופך את $SIG{__WARN__} לפטיש; עדיף no warnings '<category>' לדיכוי ממוקד ולשמור את המטפל לניתוב או הסלמה.

# wipe out *all* compile-time warnings, then switch on at runtime
BEGIN { $SIG{'__WARN__'} = sub { warn $_[0] if $DOWARN } }
my $foo = 10;
my $foo = 20;                       # duplicate-my silenced
$DOWARN = 1;
warn "\$foo is alive and $foo";     # now shows up

warn המובנה מול use warnings#

אלה דברים שונים. אסור לבלבל ביניהם:

  • warn היא פונקציה מובנית המנפיקה הודעה יחידה כעת. אתם קוראים לה.

  • use warnings הוא pragma המאפשר קטגוריות של אבחנות זמן הידור וזמן ריצה (ערכים לא־מאותחלים, תכונות מיושנות, מטפלי קובץ לא־פתוחים, וכן הלאה). המהדר והמפרש מנפיקים את האבחנות הללו בעבורכם, באמצעות אותו מנגנון ש־warn משתמש בו.

האבחנות של ה־pragma זורמות דרך $SIG{__WARN__} בדיוק כמו קריאות warn מפורשות. no warnings '<category>' מדכא את האבחנות של ה־pragma בתיחום הלקסיקלי שלו אך אין לו השפעה על warn מפורש שכתבתם בעצמכם - אותה קריאה תמיד נורה.

דוגמאות#

דיווח על בעיה הניתנת לשחזור והמשך:

open my $fh, "<", $path
    or warn "skipping $path: $!\n" and next;

אבחנה במצב פיתוח עם מיקום מצורף:

warn "unexpected record shape";
# unexpected record shape at parser.pl line 87.

הבחנה בחריגה שנתפסה מבלי לדכא אותה:

eval { load_config() };
warn if $@;                         # surfaces "...caught at ..."

ניתוב כל אזהרה דרך logger, תוך המשך הדפסה ל־STDERR:

local $SIG{__WARN__} = sub {
    my ($msg) = @_;
    $logger->warn($msg);
    print STDERR $msg;              # preserve default visibility
};

הסלמת אזהרה מסוימת לשגיאה קטלנית:

local $SIG{__WARN__} = sub {
    die @_ if $_[0] =~ /corrupt database/;
    warn @_;                        # everything else: default path
};

העברת עצם bless לאזהרות מובנות (המקבל של הוו $SIG{__WARN__} מקבל את ההפניה, לא צורה הפוכה למחרוזת):

local $SIG{__WARN__} = sub {
    my ($w) = @_;
    if (ref($w) && $w->isa('MyApp::Warning')) {
        $logger->record($w);
    }
    else {
        print STDERR $w;
    }
};
warn MyApp::Warning->new(code => 'SLOW_IO', detail => $path);

מקרי קצה#

  • רשימה עם שני איברים או יותר מופכת למחרוזת ומשורשרת: warn "bad record ", $n, ": ", $raw. כלל השורה החדשה חל על התוצאה המשורשרת.

  • רשימה ריקה (warn; או warn "";) מפעילה את מסלול ההתפשטות, לא הודעה רעננה.

  • אזהרה בערך הפניה בתוך מטפל $SIG{__WARN__}: המטפל מקבל את ההפניה ללא שינוי. אם לא מותקן מטפל, ההפניה הופכת למחרוזת ל־STDERR דרך ה־overload של "" שלה (או ברירת המחדל של Perl MyClass=HASH(0x...)).

  • warn בתוך $SIG{__WARN__}: אינו נכנס מחדש למטפל. הקריאה כותבת ל־STDERR כאילו לא הותקן מטפל. זה מה שהופך את הניב ”העברה דרך“ לבטוח.

  • warn במהלך הריסה גלובלית: עדיין עובד, אך STDERR עשוי כבר להיות סגור במקרים פתולוגיים. אזהרות ממטפלי DESTROY הרצים ביציאת המפרש יכולות להיעלם.

  • STDERR סגור או מופנה: warn כותב למה ש־STDERR מצביע אליו כעת. אם STDERR סגור, הכתיבה נכשלת בשקט; שגיאה אינה מועלית, מכיוון ש־warn עצמו אינו בודק.

  • אין קשר ל־$\ / $,: הוספת local $\ = "\n" אינה גורמת ל־warn "x" להדפיס שורה חדשה. כלל השורה החדשה הגוררת הוא המנגנון היחיד להוספת שורה חדשה עבור warn.

הבדלים מהמקור#

תואם במלואו ל־Perl 5.42 במקור.

ראו גם#

  • die - אותם כללי עיצוב (שורה חדשה גוררת מדכאת מיקום, הפניות עוברות דרך ללא שינוי), אך מעלה חריגה במקום לדווח ולהמשיך

  • eval - זווג עם הצורה ללא ארגומנט של warn עבור הניב ”תפיסה, בדיקה, החזרה לפני השטח“

  • $@ - המקור ש־warn ללא ארגומנט מדווח ממנו

  • $SIG{__WARN__} - הוו שמחליף את הכתיבה ב־STDERR בברירת מחדל; יש להשתמש בו לניתוב, סינון, או הסלמה

  • Carp - carp, cluck, croak, confess: אזהרות וחריגות המדווחות מנקודת המבט של הקורא במקום מאתר הקריאה, וזה כמעט תמיד מה שספרייה רוצה