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

package#

מצהיר על מרחב השמות בזמן ההידור עבור ההצהרות שלאחריו.

package אומר למהדר באיזו טבלת סמלים להשתמש בעת פתרון שמות לא־מוסמכים בקוד שהוא עומד לפענח. הוא אינו יוצר חבילה במובן כלשהו של זמן ריצה - חבילות צצות לקיום בפעם הראשונה שמשהו מאוחסן בהן. מה שהצהרת package באמת עושה הוא להפנות את המהדר מחדש: מכאן והלאה, $foo משמעו $NAMESPACE::foo, &bar משמעו &NAMESPACE::bar, וכן הלאה, עד להצהרת package הבאה או עד סוף התחום הסובב.

תקציר#

package NAME;
package NAME VERSION;
package NAME     { ... }
package NAME VER { ... }

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

package היא הוראת זמן־הידור, לא ביטוי. אין לה ערך זמן ריצה שימושי - התייחסו אליה כאל הצהרה. ההשפעה שלה היא על המפענח: כל המזהים הלא־מוסמכים שלאחר מכן נפתרים בטבלת הסמלים של NAME עד שהתחום מסתיים.

לצורה עם VERSION יש תופעת לוואי גלויה אחת: היא קובעת את $NAME::VERSION לעצם version הנבנה מ־VERSION. הדבר מתרחש פעם אחת בדיוק לכל הצהרת package NAME VERSION, בזמן ההידור.

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

  • החבילה הנוכחית בזמן ההידור. כל הצהרת package מחליפה אותה לשאר התחום. __PACKAGE__ מחזיר את הערך הנוכחי בכל נקודה במקור.

  • $NAME::VERSION - נקבע כאשר הארגומנט VERSION מסופק. קבעו אותו פעם אחת בלבד לכל חבילה.

  • טבלת הסמלים (stash) של היעד נוצרת בשימוש הראשון. ה-stash של חבילה הוא בעצמו hash בשם %NAME:: (כך ש-stash של main הוא %main::), שמפתחותיו הם שמות הסמלים הלא-מוסמכים שהוא מחזיק. דבר אינו מאוכלס על ידי משפט ה-package עצמו; הצהרות מאוחרות יותר (sub, our, השמות ל-$NAME::foo וכדומה) ממלאות אותו.

ארבע הצורות#

package NAMESPACE#

מעביר את חבילת זמן־ההידור ל־NAMESPACE מנקודה זו עד סוף התחום הנוכחי (בלוק סובב, קובץ, או eval). זוהי הצורה הקלאסית של ״חבילה אחת לקובץ״:

package My::Thing;

sub new { ... }         # defines &My::Thing::new
our $count = 0;         # defines $My::Thing::count

1;

package NAMESPACE VERSION#

אותו תיחום כמו הצורה העירומה, בנוסף הוא קובע את $NAMESPACE::VERSION לעצם version. VERSION חייב להיות ליטרל גרסה קפדן: או עשרוני חיובי (1.23, 0.001) או מחרוזת־v עשרונית מנוקדת עם v מוביל ולפחות שלושה רכיבים (v1.2.3). סימון מעריך אינו מותר.

package My::Thing 1.042;
package My::Thing v1.2.3;

קבעו את $VERSION פעם אחת בלבד לכל חבילה - הצהרת package NAME VERSION שנייה באותה חבילה דורסת את הראשונה, וצרכני use Module VERSION רואים רק את הערך הסופי.

package NAMESPACE BLOCK#

מתחם לקסיקלית את החלפת החבילה ל־BLOCK. בתוך הסוגריים המסולסלים חבילת זמן־ההידור היא NAMESPACE; מחוץ לסוגר הסוגר החבילה הקודמת משוחזרת. זוהי הצורה היחידה החוזרת אוטומטית.

package Outer;
our $x = 1;             # $Outer::x

package Inner {
    our $y = 2;         # $Inner::y
}

our $z = 3;             # $Outer::z again

package NAMESPACE VERSION BLOCK#

צורת הבלוק עם ליטרל גרסה. התחום חוזר בסוגר הסוגר; $NAMESPACE::VERSION נשאר מוגדר.

package My::Sub v0.9.1 {
    sub ping { "pong" }
}

מה package מתחם ומה הוא אינו מתחם#

package משפיע על משתנים דינמיים (של חבילה) ועל פתרון שמות לא־מוסמכים. הוא אינו משפיע על לקסיקלים:

  • my, state - נוצרים ב־pad הלקסיקלי, בלתי־נראים לאיתור חבילה. הצהרת package אינה עושה דבר עבורם.

  • local - מתחם דינמית משתנה חבילה, ששייך עדיין לכל חבילה ששמו המוסמך נוקב בה.

  • our - מצהיר על כינוי לקסיקלי למשתנה חבילה בחבילת זמן־ההידור הנוכחית. זה המנגנון המאפשר ל־our $count בתוך package My::Thing להיות כינוי ל־$My::Thing::count.

החלפת חבילות לאחר הצהרת our אינה ממקדת מחדש את הכינוי: הכינוי נקשר לחבילה שהייתה בתוקף כש־our הודר.

package Foo;
our $x;                 # aliases $Foo::x
package Bar;
$x = 1;                 # still writes $Foo::x

אינטראקציה עם use v5.36 וחדשים יותר#

use v5.36 (וכל use v5.36 ואילך) מפעיל strict ו־warnings באופן מובלע. ברגע ש־strict פעיל, משתני חבילה לא־מוסמכים דורשים הצהרת our (או הסמכה מלאה). בשילוב עם הצהרת package, שלד הקובץ המודרני האידיומטי הוא:

package My::Thing 1.00;

use v5.36;              # strict, warnings, say, signatures, ...

our @EXPORT_OK = qw(thingify);

sub thingify { ... }

1;

הצורה package NAME VERSION ו־use VERSION הן בלתי־תלויות: הראשונה קובעת את $My::Thing::VERSION; השנייה מפעילה תכונות שפה עבור הקובץ הנוכחי.

מזהים מיוחדים שמשמעותם תמיד main::#

קבוצה קטנה של מזהים נכפים לתוך החבילה main:: ללא תלות ב־package הנוכחי:

  • STDIN, STDOUT, STDERR, ARGV, ARGVOUT

  • @ARGV, @INC, %ENV, %SIG, %INC

  • כל משתני הפיסוק: $_, $!, $@, @_, וכו׳.

  • המזהה בן התו הבודד _, בכל סימניו: ה-filehandle של הקו התחתון שבו משתמשים stat ובדיקות הקבצים -X, הסקלר $_ והמערך @_.

כתיבה ל־$! בתוך package Foo עדיין כותבת ל־$main::!. הדבר מכוון: שמות אלה היו חסרי תועלת אילו עברו עם החבילה.

דוגמאות#

קובץ מודול מינימלי. שם הקובץ חייב להתאים לשם החבילה (require ממיר :: למפריד הספריות):

# lib/My/Greeter.pm
package My::Greeter 1.00;
use v5.36;

sub new  { my ($cls, %a) = @_; bless { %a }, $cls }
sub greet { my $self = shift; "hello, $self->{name}\n" }

1;

שתי חבילות בקובץ אחד באמצעות צורת הבלוק. התחום חוזר אוטומטית, אז ה־1; בתחתית אינו שייך לחבילה מסוימת - הוא מוערך בכל חבילה שהייתה פעילה בראש הקובץ (main עבור סקריפט, החבילה של הקובץ עצמו עבור מודול):

package My::Thing {
    sub do_stuff { ... }
}

package My::Thing::Helper {
    sub helper { ... }
}

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

package A;
sub one { 1 }           # &A::one

package B;
sub two { 2 }           # &B::two

package A;
sub three { 3 }         # &A::three

קביעת גרסה וקריאתה בחזרה. שימו לב ש־$VERSION הוא עצם version, לא מחרוזת רגילה; המירו למחרוזת או השוו עם version:

package Foo 1.23;

say $Foo::VERSION;      # 1.23
say ref $Foo::VERSION;  # version

our בתוך חבילה נותן לכם כינוי בעל תיחום לקסיקלי למשתנה חבילה - הדרך הקנונית להצהיר על גלובלים ברמת מודול תחת strict:

package Counter;
use v5.36;

our $count = 0;         # aliases $Counter::count
sub bump { $count++ }

מקרי קצה#

  • package NAMESPACE VERSION מקבל רק ליטרלים קפדנים של גרסה. סימון מעריך (1e3), מחרוזות לא־מספריות, ומחרוזות־v בנות שני־רכיבים (v1.2) הן שגיאות הידור.

  • קביעת $VERSION פעמיים באותה חבילה (בין אם בשתי הצהרות package NAME VERSION או על־ידי השמה מפורשת אחרי package NAME VERSION) חוקית אבל מבלבלת - use Module VERSION בודק את הערך הסופי, וכלי CPAN קוראים את זה שהם מוצאים ראשון. הצהירו על הגרסה פעם אחת.

  • צורת הבלוק היא תחום לקסיקלי נפרד. משתני my ו־state המוצהרים בתוך package NAME { ... } אינם נראים בחוץ, בדיוק כמו כל בלוק אחר.

  • package NAMESPACE ללא הצהרה או בלוק נגרר משפיע על שאר הקובץ. package בראש סקריפט מעביר את הסקריפט לצמיתות מחוץ ל־main, מה שאומר ש־$main::ARGV[0] הוא עדיין רשימת הארגומנטים שלכם אבל גלובלים שהוצהרו מחדש שייכים לחבילה החדשה. הדבר כמעט אף פעם אינו מה שסקריפט רוצה.

  • קובץ המכיל רק package Foo; ואין קוד אחר עדיין מהדר נקי ויוצר את ה־stash של Foo:: בהפניה הראשונה - אבל require עליו מחזיר את הערך של ההצהרה האחרונה, שהיא הצהרת ה־package עצמה (שקר). שימו 1; בסוף כל קובץ מודול.

  • צורות בלוק מקוננות משחזרות את החבילה הסובבת המיידית, לא את main:

    package Outer;
    package Inner {
        package Innermost {
            # __PACKAGE__ is Innermost
        }
        # __PACKAGE__ is Inner again
    }
    # __PACKAGE__ is Outer again
    
  • package בתוך eval. החלפת החבילה מתוחמת לגוף ה־eval. סמלים שנוצרו במהלך ה־eval נשמרים ב־stashes שלהם (stashes הם גלובליים), אבל חבילת זמן־ההידור חוזרת כאשר ה־eval מסתיים.

  • גרש כמפריד חבילה. הגרש היה מפריד מרחבי-השמות המקורי של פרל: $main'sail פירושו היה $main::sail, הרבה לפני ש-:: היה קיים. הוא שורד רק לצורך קריאה של קוד מתקופת Perl 4 ומושבת תחת חבילות תכונות מודרניות, כך שתוכנית עכשווית שנכתבה עם use v5.36 (או כל חבילה עדכנית) לא תזהה אותו. אל תכתוב אותו; הנקודתיים הכפולות :: הן המפריד היחיד שקוד עכשווי צריך להשתמש בו.

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

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

ראו גם#

  • use - טעינת מודול בזמן הידור וייבוא סמלים מהחבילה שלו; משולב בדרך כלל עם הצהרת package בראש הקובץ הנטען

  • require - טעינת מודול או קובץ בזמן ריצה; הצהרת ה־package של הקובץ הנטען קובעת איזה stash ההצהרות שלו מאכלסות

  • bless - שיוך הפניה לחבילה כך שקריאות מתודה ינותבו לתת־השגרות של אותה חבילה; הדבק בין package לתכנות מונחה־עצמים

  • my - הצהרה על משתנה לקסיקלי ש־package אינו משפיע עליו; המקבילה לגלובלים של חבילה

  • our - הצהרה על כינוי לקסיקלי למשתנה חבילה בחבילת זמן־ההידור הנוכחית; הדרך הבטוחה־ל־strict להשתמש בגלובלים ברמת מודול

  • local - תיחום דינמי של ערך משתנה חבילה מבלי לשנות לאיזו חבילה הוא שייך