מודולים

require#

טעינת קובץ מקור Perl בזמן ריצה, או דרישת גרסת Perl מינימלית.

ל־require שלוש צורות העושות דברים שונים למדי. עם מספר גרסה הוא טוען שהמפרש הרץ חדש מספיק. עם bareword הוא טוען מודול על־ידי המרת Foo::Bar ל־Foo/Bar.pm וחיפוש ב־@INC. עם מחרוזת זמן ריצה או $_ הוא טוען שם קובץ מילולית. כל השלוש הן פעולות זמן ריצה - בניגוד ל־use, שהוא require + import עטופים בבלוק BEGIN של זמן הידור.

תקציר#

require VERSION
require EXPR
require

מה מוחזר#

עבור צורת בדיקת הגרסה: 1 אם ה־Perl הרץ חדש מספיק; אחרת נזרקת חריגה (Perl vX.Y.Z required--this is only ...). אין מה לבדוק.

עבור צורות טעינת הקובץ: ערך האמת שמוחזר על־ידי ההצהרה האחרונה של הקובץ הנטען, או 1 אם הקובץ מפעיל את התכונה module_true (ברירת מחדל תחת use v5.38 ואילך). require שני של אותו נתיב מחזיר 1 בלי להריץ מחדש את הקובץ. כישלון זורק חריגה - או שגיאת הידור/זמן ריצה מהקובץ, Can't locate Foo/Bar.pm in @INC ..., או Foo/Bar.pm did not return true value.

יש לעטוף ב־eval כאשר רוצים לבדוק האם מודול ניתן לטעינה:

eval { require Some::Optional::Module };
if ($@) { ... }                    # module missing or broken

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

  • @INC - נתיב החיפוש עבור צורות bareword ושמות קבצים יחסיים. ערכים יכולים להיות מחרוזות ספריה, הפניות קוד, הפניות מערך, או עצמים מבורכים (ראו הוואי @INC להלן).

  • %INC - ממפה את שם הקובץ המבוקש (Foo/Bar.pm) לנתיב המוחלט שנטען. require פונה אליו כדי להימנע מטעינה כפולה וקובע אותו בהצלחה. ערך של undef מסמן קובץ שהידורו נכשל.

  • $_ - בשימוש כשם הקובץ כאשר require נקרא ללא ארגומנט.

  • ${^HOOK}{require__before} ו־${^HOOK}{require__after} - הפניות קוד אופציונליות הרצות סביב כל require, זמינות למעטפות מעקב והנמקה.

שלוש הצורות#

require VERSION - בדיקת Perl מינימלי#

VERSION הוא או v-string כגון v5.38.0 (מושווה מול $^V) או ליטרל מספרי כגון 5.038000 (מושווה מול $]). אם המפרש הרץ ישן יותר, require זורק.

require v5.38;        # preferred
require 5.038;        # numeric; same effect
require 5.038_000;    # same; pre-5.6 syntax

זוהי בדיקת זמן ריצה. אם רוצים שהבדיקה תתרחש בזמן הידור (כך שהסקריפט לעולם לא ייפעל על Perl ישן), יש להשתמש ב־use VERSION במקום:

use v5.38;            # compile-time equivalent

require EXPR כאשר EXPR הוא bareword - מודול לפי שם#

bareword מתפרש כשם מודול. require מחליף כל :: ב־/ ומצרף .pm, ואז מחפש ב־@INC:

require Foo::Bar;     # looks for Foo/Bar.pm in @INC

צורה זו גם מבצעת autovivify ל־stash בזמן הידור - האש החבילה Foo::Bar:: קופץ לקיום גם אם הטעינה נכשלת מאוחר יותר. אין סמלים מיובאים; require רק טוען קוד.

לפני שמנסה את Foo/Bar.pm, require מחפש את Foo/Bar.pmc באותה ספריה ומעדיף אותו אם נמצא. ההוו של .pmc מאפשר לכלי בנייה לשלוח קבצים נלווים מהודרים־מראש לצד מקורות.

require EXPR כאשר EXPR הוא מחרוזת - קובץ לפי נתיב#

כל ביטוי שאינו bareword מטופל כשם קובץ מילולי. ללא תרגום ::, ללא צירוף .pm, ללא autovivification של stash:

require "Foo/Bar.pm";           # explicit .pm path
require "$config_dir/init.pl";  # arbitrary filename

my $class = 'Foo::Bar';
require $class;                 # ERROR: looks for file "Foo::Bar"

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

(my $file = "$class.pm") =~ s{::}{/}g;
require $file;

eval "require $class; 1" or die $@;

אם EXPR מושמט לחלוטין, $_ בשימוש.

שומר ה־%INC - קבצים נטענים נשארים טעונים#

לפני החיפוש ב־@INC, require פונה ל־%INC. אם שם הקובץ המבוקש נוכח ויש לו ערך אמת, require מחזיר 1 מיידית בלי לקרוא מחדש את הקובץ. אם הערך הוא undef, טעינה קודמת נכשלה ו־require זורק Compilation failed in require - Perl מסרב לנסות שוב קובץ שכבר התפוצץ פעם אחת במפרש זה.

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

הוו רשאי לקבוע את %INC בעצמו; אם לא, require רושם את ההוו כ״מקור״ של הטעינה.

מוסכמת ה־1;#

היסטורית כל קובץ הניתן לטעינה היה חייב להחזיר ערך אמת כביטוי האחרון שלו, אחרת require זרק filename did not return true value. הדרך הקנונית להבטיח זאת היא 1; מסיים:

package My::Thing;
# ... module code ...
1;                                 # mandatory, pre-5.38

מ־Perl 5.38 ואילך, התכונה module_true - מופעלת כברירת מחדל תחת use v5.38 ואילך - גורמת לכל קובץ שעובר require להחזיר אמת באופן מובלע בהידור מוצלח. קבצים המצטרפים אינם צריכים יותר 1;. קבצים שלא, עדיין כן.

זה משפיע רק על יחידת ההידור שהפעילה את התכונה; מודולים legacy שנטענים על־ידי קורא מודרני עדיין צריכים את ה־1; שלהם.

כאשר הקובץ הנטען אכן מחזיר ערך ו־module_true כבוי, אותו ערך הוא מה ש־require מחזיר - אך רק בטעינה הראשונה. קריאות require עוקבות של אותו קובץ מחזירות 1 ממטמון ה־%INC. כדי ללכוד את ערך ההחזרה של קובץ באופן אמין, יש להשתמש ב־do:

my $config = do "config.pl"
    or die "config.pl: ", $@ || $!;

הוואי @INC - הפניות קוד, הפניות מערך, ועצמים#

ערכים ב־@INC אינם חייבים להיות מחרוזות ספריה. הפניה השמורה ב־@INC נקראת הוו ומקבלת הזדמנות לספק את ה־require.

הפניה לתת־שגרה#

נקרא עם שני ארגומנטים: הפניית הקוד עצמה ושם הקובץ (Foo/Bar.pm). היא צריכה להחזיר או כלום (משמעות ״אינני יכול לטפל בזה; נסה את הערך הבא״) או עד ארבעה ערכים:

  1. הפניה סקלרית לטקסט מקור הקודם לקובץ.

  2. מטפל קובץ שממנו נקרא שאר המקור.

  3. תת־שגרת גנרטור או מסנן (ראו perldoc perlfunc לפרוטוקול המדויק).

  4. מצב אופציונלי המוחזר לגנרטור.

push @INC, sub {
    my ($self, $filename) = @_;
    return unless $filename eq 'Virtual/Module.pm';
    open my $fh, '<', \"package Virtual::Module; 1;";
    return $fh;
};

הפניית מערך#

האיבר הראשון הוא הפניית קוד או עצם כלעיל; השאר הוא מצב שההוו יכול לקרוא בכל קריאה. כשהאיבר הראשון הוא עצם עם מתודה INC או INCDIR, המתודה מקבלת את הפניית המערך כארגומנט השלישי שלה.

push @INC, [\&my_loader, $db_handle, $cache];

עצם מבורך#

אם לעצם יש מתודה INC או INCDIR, require קורא לאותה מתודה; אחרת, אם העצם הוא גם הפניית קוד, הוא מופעל כמו הפניית תת־שגרה פשוטה. מתודות INC חייבות להיות מוצהרות עם שמן המוסמך במלואו (sub Foo::INC { ... }), משום שהסמל הלא־מוסמך INC מקובע לחבילה main.

הוו רשאי לעדכן בחופשיות את %INC כדי לרשום את הנתיב שסיפק; אם לא, require שומר את הפניית ההוו עצמה.

require מול use#

use Foo::Bar qw(x y);

# is almost exactly:

BEGIN {
    require Foo::Bar;
    Foo::Bar->import(qw(x y));
}

היבט

use

require

מתי הוא רץ

זמן הידור (בתוך BEGIN)

זמן ריצה

קורא ל־import

כן

לא

bareword ::/

כן

כן, כאשר נקרא על bareword

צורת בדיקת גרסה

use v5.38

require v5.38

טוב עבור

תלויות קבועות

מודולים אופציונליים / קשורים מאוחר

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

דוגמאות#

גרסת Perl מינימלית בזמן ריצה:

require v5.38;

טעינת מודול bareword - מחפש ב־@INC, עושה autovivify ל־Data::Dumper:: בזמן הידור:

require Data::Dumper;
Data::Dumper->import;
print Data::Dumper::Dumper(\%ENV);

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

my $have_json = eval { require JSON::PP; 1 };
if ($have_json) {
    print JSON::PP->new->encode($data);
}

טעינת מודול ששמו מחושב בזמן ריצה. יש להמיר לנתיב שם קובץ; require $class יחפש קובץ מילולי בשם Foo::Bar:

my $driver = $ENV{DB_DRIVER} // 'SQLite';
my $class  = "DBD::$driver";
(my $file  = "$class.pm") =~ s{::}{/}g;
require $file;

טעינת קטע הגדרה לפי שם נתיב, תוך שמירת ערך ההחזרה שלו - שימו לב ל־do, לא require, משום שאנחנו רוצים את הערך בכל קריאה:

my $config = do '/etc/myapp/config.pl'
    or die "config load failed: ", $@ || $!;

התקנת הוו @INC המגיש מודול וירטואלי יחיד ממחרוזת בזיכרון:

unshift @INC, sub {
    my ($self, $filename) = @_;
    return unless $filename eq 'MyApp/Version.pm';
    my $src = "package MyApp::Version; our \$VERSION = '1.23'; 1;";
    open my $fh, '<', \$src;
    $INC{$filename} = '(generated)';
    return $fh;
};
require MyApp::Version;

מקרי קצה#

  • bareword מול מחרוזת: require Foo::Bar ו־require "Foo::Bar" אינם זהים. צורת ה־bareword מתורגמת ל־Foo/Bar.pm; צורת המחרוזת מחפשת קובץ ששמו מילולית Foo::Bar.

  • שמות מחלקה מחושבים: require $class כאשר $class מחזיק 'Foo::Bar' מחפש קובץ בשם Foo::Bar, לא Foo/Bar.pm. יש לתרגם את השם בעצמכם, או להשתמש ב־eval "require $class" כאשר השם אמין.

  • ללא ארגומנט: require; משתמש ב־$_ כשם הקובץ. נדיר בקוד מודרני; כמעט תמיד תאונה.

  • ניסיונות הזדמנות שנייה אינם עובדים: אם require נכשל באמצע ההידור, %INC רושם undef עבור אותו שם קובץ. require מאוחר יותר של אותו שם רואה את ה־undef וזורק Compilation failed in require בלי להריץ מחדש את הקובץ. יש למחוק את הערך ב־%INC אם באמת רוצים לנסות שוב (זהו קצה חד; עדיף לתקן את הכישלון הבסיסי).

  • הסרת ה־. היחסי: . הוסר מ־@INC ברירת המחדל ב־Perl 5.26. סקריפט שנהג למצוא את Foo/Bar.pm לידו צריך כעת להוסיף את הספריה שלו במפורש (use FindBin; use lib $FindBin::Bin;).

  • הצללת .pmc: אם Foo/Bar.pmc קיים באותה ספריה כמו Foo/Bar.pm, ה־.pmc מנצח. קובצי .pmc מיושנים הם מלכודת קלאסית של ״למה העריכה שלי לא נכנסת לתוקף״.

  • פרסור require(EXPR): require מפורסר כאופרטור אונרי בעל שם; require EXPR + 1 משמעו require(EXPR + 1). יש להשתמש בסוגריים מפורשים כאשר הארגומנט הוא ביטוי לא־טריוויאלי.

  • autovivification של stash: require Foo::Bar יוצר את ה־stash של Foo::Bar:: גם אם הקובץ חסר. בדיקות defined &Foo::Bar::some_sub במורד הזרם עלולות לעבור את שלב ״החבילה קיימת״ אך להיכשל בשלב ״תת־השגרה קיימת״.

  • מטפל קובץ מהוו חייב להיות אמיתי: מטפלי קובץ קשורים (tied) נדחים בשקט על־ידי פרוטוקול ההוו; הטיפול נופל מהקצה ו־require מדווח ״לא נמצא״. יש להשתמש ב־typeglob אמיתי.

  • INC חייב להיות מוסמך במלואו במחלקות הוו: sub Foo::INC { ... } עובד; sub INC { ... } בתוך package Foo מתקין main::INC בגלל כלל חבילה מקובע.

  • require() קשה לעטיפה: מודולים רבים בוחנים את מחסנית הקריאות כדי למצוא את הקורא שלהם. מעטפת שמוסיפה frame לעתים קרובות שוברת אותם. עדיף את הוואי ${^HOOK}{require__before} / ${^HOOK}{require__after} (נוספו ב־5.38) למעקב.

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

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

ראו גם#

  • use - require + import בזמן הידור; הדרך הרגילה למשוך מודול שתלויים בו ללא תנאי

  • do - טעינת קובץ והחזרת ערכו בכל קריאה, ללא שמירת %INC במטמון וללא כלל ״חייב להחזיר אמת״

  • import - המתודה ש־use קורא לאחר require; require לעולם אינו קורא לה בשבילכם

  • @INC - נתיב חיפוש שאליו פונים עבור טעינות bareword ושמות קבצים יחסיים; מקבל מחרוזות ספריה, הפניות קוד, הפניות מערך, ועצמים כהוואי

  • %INC - מטמון בעל ערך־אחד־לקובץ־טעון שגורם ל־require להיות אידמפוטנטי ורושם מהיכן הגיע כל מודול

  • eval - לעטוף את require כשמותר לטעינה להיכשל