תיחום · מודולים · מחלקות ותכנות מונחה־עצמים
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- תיחום דינמי של ערך משתנה חבילה מבלי לשנות לאיזו חבילה הוא שייך