תיחום · מודולים

import#

לאכלס את מרחב השמות של הקורא בשמות שמודול בוחר לייצא.

import אינו פונקציה מובנית. הוא מתודת מחלקה שמודול מגדיר כך של־use יהיה היכן להעביר את רשימת הארגומנטים. כאשר כותבים use Module LIST, Perl טוען את המודול ואז קורא ל־Module->import(LIST) בזמן הידור, בחבילה שמכילה את הוראת ה־use. כל מה שהמתודה הזו עושה - להתקין תת־שגרות ב־stash של הקורא, להפוך ביטי תכונה, להגדיר דגלי פרגמה - הוא כל חוזה ה־import של המודול.

רוב המודולים לעולם לא כותבים import ביד; הם יורשים אותו מ־Exporter ומצהירים על @EXPORT / @EXPORT_OK במקום זאת. פרגמות (strict, warnings, feature) כותבות import משלהן משום שמה שהן מתקינות הוא מצב לקסיקלי, לא תת־שגרות.

תקציר#

Module->import;
Module->import(LIST);
Module->import(@symbols);

בתוך מודול, ההגדרה נראית כך:

package My::Module;
sub import {
    my ($class, @args) = @_;
    # install names into caller's package
}

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

ערך ההחזרה של import מושלך על־ידי use. מודול שנקרא ישירות כמתודה יורש את המוסכמה שהמחבר בחר - לפי המוסכמה, לא להחזיר שום דבר שימושי.

האפקט הנראה הוא בחבילה של הקורא: לאחר ש־use Module qw(foo bar) חוזר, foo ו־bar ניתנים לקריאה ללא תחילית חבילה מהקוד שהריץ את ה־use.

איך use קורא ל־import#

use Module LIST הוא, בפועל:

BEGIN {
    require Module;
    Module->import(LIST);
}

שלוש השלכות נובעות משוויון זה:

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

  • caller משקף את בלוק ה־BEGIN, לא את תת־השגרה הסובבת. מתודת import שבוחנת caller(0) רואה את החבילה שכתבה use Module, וזה בדיוק מה שהיא רוצה; היא אינה רואה את תת־השגרה שמכילה את הוראת ה־use.

  • רשימה נעדרת מול רשימה ריקה. use Module ללא רשימה קורא ל־Module->import ללא ארגומנטים - המודול מתקין את ברירות המחדל שלו. use Module () עם רשימה ריקה מפורשת מדלג על קריאת ה־import לחלוטין. זהו המבנה עבור ״לטעון את הקובץ אך לא לגעת במרחב השמות שלי.״

no Module LIST הוא תמונת המראה: הוא קורא ל־Module->unimport(LIST) במקום import. פרגמות משתמשות בזה כדי לכבות תכונות לתחום הלקסיקלי העוטף.

הגדרת מתודת import#

המסלול הנפוץ הוא ירושה מ־Exporter:

package My::Utils;
use Exporter 'import';                 # installs Exporter::import
our @EXPORT_OK = qw(slurp trim);
sub slurp { ... }
sub trim  { ... }
1;

קוראים כותבים אז:

use My::Utils qw(slurp trim);
slurp($path);

import שנכתב ביד יש לו אותה צורה כמו כל מתודה - הוא מקבל את שם המחלקה כארגומנט הראשון שלו ואת רשימת הארגומנטים של use כשאר:

package My::Feature;
sub import {
    my ($class, @flags) = @_;
    my $caller = caller;
    no strict 'refs';
    for my $name (@flags) {
        *{ "${caller}::${name}" } = \&{ "${class}::${name}" };
    }
}

שם החבילה של הקורא מגיע מ־caller, לא מ־$class - $class הוא איזה מודול שהמשתמש ציין בשורת ה־use.

דוגמאות#

ייבוא ברירת מחדל - מה שרשימת ה־@EXPORT של המודול מכילה:

use List::Util;                        # imports nothing by default
use File::Basename;                    # imports basename, dirname, ...

רשימת ייבוא מפורשת - רק השמות שמבקשים:

use List::Util qw(sum min max);
my $total = sum(1, 2, 3);              # 6

רשימה ריקה - לטעון את הקובץ, לא לגעת בשום דבר:

use POSIX ();                          # no POSIX::* names imported
my $pi = POSIX::acos(-1);              # fully qualified call

ייבוא מפרגמה - אפקט לקסיקלי בבלוק העוטף:

use strict;
use warnings;
{
    no warnings 'uninitialized';       # unimport in this block only
    print "x=", $x, "\n";
}

קריאה ל־import ישירות לאחר require בזמן ריצה:

require My::Plugin;
My::Plugin->import(@config);           # deferred to runtime on purpose

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

מקרי קצה#

  • אין דבר כזה import מובנה. print import(@list) קורא לתת־השגרה בשם import בחבילה הנוכחית (אם קיימת); זה אינו אופרטור ברמת השפה. כללי ניתוח חלים כפי שהם חלים על כל תת־שגרה מוגדרת־משתמש.

  • רשימה מושמטת מול רשימה ריקה היא מקור הבלבול הנפוץ ביותר. use Mod קורא ל־import; use Mod () אינו. ה־() אינו ריק סגנוני - זהו אות.

  • ארגומנט גרסה מריץ VERSION, לא import. use Mod 1.23 LIST קורא ל־Mod->VERSION(1.23) לפני Mod->import(LIST). use Mod 1.23 חשוף הוא עדיין בדיקת גרסה ואחריה import של ברירת מחדל. לבדיקת גרסה ודילוג על ייבוא, יש לכתוב use Mod 1.23 ().

  • אין import מוגדר בכלל. אם המודול לא כותב ולא יורש import, use Module LIST עם רשימה לא־ריקה אינו שוגה - קריאת המתודה נופלת בשקט מכיוון ש־UNIVERSAL::can('import') מחזיר שקר ו־use מתייחס לזה כ־״אין מה לעשות.״ LIST לא־ריקה אז למעשה מתעלמים ממנה, מה שכמעט אף פעם אינו מה שהקורא רצה.

  • import רץ פעם אחת לכל הוראת use, לא פעם אחת לכל תהליך. use Mod qw(foo); use Mod qw(bar); קורא ל־import פעמיים, גם אם הקובץ נטען רק פעם אחת - @INC / %INC מסננים את טעינת הקובץ, לא את קריאת המתודה.

  • התקנת סמלים אינה אוטומטית. כתיבת מתודת import שרק חוזרת לא עושה דבר; חייבים להשים אל תוך ה־stash של הקורא (*{"${caller}::name"} = \&sub) או להאציל ל־Exporter.

  • פרגמות בדרך כלל מתקינות מצב לקסיקלי, לא תת־שגרות ברמת חבילה. ה־import שלהן קורא לפונקציות כמו warnings::import_into או משנה את %^H; זוהי הסיבה שאפקט של פרגמה תחום לבלוק העוטף במקום להתמיד בחבילה.

הבדלים מ־upstream#

תואם מלא ל־upstream Perl 5.42.

ראו גם#

  • use - הטוען בזמן הידור שמפעיל את import; הבנת אחד דורשת את האחר

  • no - המראה של use; קורא ל־unimport עם אותם כללי העברת ארגומנטים

  • require - טוען את הקובץ מבלי לקרוא ל־import; יש לשייך עם Module->import(...) מפורש כאשר רוצים לדחות או לדלג על הדיספאץ« בזמן הידור

  • package - מגדיר את מרחב השמות שמתודת import מאכלסת מנקודת המבט של הקורא

  • caller - איך מתודת import מגלה לאיזו חבילה להתקין שמות

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