# מטפלי קובץ קשורים מטפל קובץ קשור מנתב מחדש קלט/פלט באותו אופן שבו סקלר קשור מנתב מחדש קריאות וכתיבות. הדפיסו אליו וה־`PRINT` שלכם רץ; קראו שורה וה־`READLINE` שלכם רץ. השימושים הקלאסיים הם הפניית פלט למקום לא־רגיל (אל מחרוזת, לרוחב רשת, דרך מסנן) והטמעת Perl בתוכנית מארחת שזקוקה לטיפול מיוחד ב־`STDOUT` וב־`STDERR`. הממשק גדול יותר מהאחרים אך ברובו אופציונלי: אתם מממשים רק את הפעולות שהמטפל אכן יקבל. התפריט המלא נמצא בעמוד העזר [`tie`](../../p5/core/perlfunc/tie.md); פרק זה בונה מחלקה ומסביר את הווים ואת תזמונם. ## מחלקה שלמה מטפל לכתיבה בלבד שאוסף למחרוזת את כל מה שמודפס אליו: ```perl use v5.36; package Collector { sub TIEHANDLE { my $class = shift; my $buf = ''; return bless \$buf, $class } sub PRINT { my $self = shift; $$self .= join($, // '', @_); return 1 } sub PRINTF { my $self = shift; my $fmt = shift; $$self .= sprintf($fmt, @_); return 1 } sub buffer { my $self = shift; return $$self } } tie *OUT, 'Collector'; print OUT "hello "; print OUT "world\n"; printf OUT "%d items\n", 3; my $obj = tied *OUT; print $obj->buffer; # hello world # 3 items ``` העצם הוא הפניית סקלר שעברה blessed ומחזיקה את הטקסט שנצבר. אל מתודת ה־`buffer` הנוספת מגיעים דרך [`tied`](../../p5/core/perlfunc/tied.md), לא דרך פעולת קלט/פלט כלשהי - זו הדרך הסטנדרטית שבה מחלקת tie חושפת פעולות ללא תחביר של מטפל קובץ. ## קישור ה־glob, לא הסקלר הארגומנט הראשון אל [`tie`](../../p5/core/perlfunc/tie.md) עבור מטפל חייב להיות glob - הוא מתחיל בכוכבית: - כדי לקשור מטפל בעל שם: `tie *OUT, 'Collector'`. - כדי לקשור מטפל שמוחזק בסקלר `$fh`: `tie *$fh, 'Collector'`. כתיבת `tie $fh, ...` קושרת את ה *סקלר* `$fh`, לא את המטפל שבתוכו - טעות נפוצה ומבלבלת. ## חוזה המתודות `TIEHANDLE classname, LIST` : הבנאי; מחזיר הפניה שעברה blessed מכל סוג. הוא יכול להחזיק כל מצב פנימי שהמטפל זקוק לו. `PRINT this, LIST` : תומך ב־[`print`](../../p5/core/perlfunc/print.md) וב־[`say`](../../p5/core/perlfunc/say.md). הוא מקבל את הרשימה המודפסת. כבדו את `$,` (מפריד שדות הפלט) בין פריטים ואת `$\` (מסיים רשומת הפלט) בסוף אם אתם רוצים נאמנות מלאה - `print` אינו מכניס אותם עבורכם. `PRINTF this, format, LIST` : תומך ב־[`printf`](../../p5/core/perlfunc/printf.md). הוא מקבל את מחרוזת הפורמט ואת הארגומנטים; העבירו אותם דרך [`sprintf`](../../p5/core/perlfunc/sprintf.md) בעצמכם. `WRITE this, scalar, length, offset` : תומך ב־[`syswrite`](../../p5/core/perlfunc/syswrite.md) - הכתיבה הגולמית, מוכוונת ה־buffer, הנבדלת מ־`PRINT`. `READLINE this` : תומך ב־`<$fh>` וב־[`readline`](../../p5/core/perlfunc/readline.md). בהקשר סקלרי החזירו את השורה הבאה או `undef` בסוף הקלט; בהקשר רשימה החזירו את כל השורות הנותרות או רשימה ריקה. המחרוזות המוחזרות צריכות לכלול את מפריד רשומת הקלט `$/`, בהתאמה למה שמטפל אמיתי נותן לכם. `READ this, scalar, length, offset` / `GETC this` : תומכים ב־[`read`](../../p5/core/perlfunc/read.md) / [`sysread`](../../p5/core/perlfunc/sysread.md) וב־[`getc`](../../p5/core/perlfunc/getc.md) בהתאמה. `OPEN`, `CLOSE`, `EOF`, `BINMODE`, `FILENO`, `SEEK`, `TELL` : תומכים במובנים המתאימים כאשר משתמשים בהם על המטפל. מממשים את אלה שהגיוניים עבור המאגר התומך שלכם ומשמיטים את השאר. `DESTROY this` / `UNTIE this` : ניקוי אופציונלי, זהה בתפקידו לסוגי ה־tie האחרים. מחלקת מטפל לעיתים קרובות סוגרת כאן את המשאב התומך שלה. ## תזמון הקריאה - `print FH @list` ו־`say FH @list` → `PRINT`. `say` בנוסף עושה localise ל־`$\` אל `"\n"` סביב הקריאה, ולכן `PRINT` שמכבד את `$\` מטפל ב־`say` ללא מקרה מיוחד. - `printf FH $fmt, @args` → `PRINTF`. - `syswrite FH, $buf, $len, $off` → `WRITE`. - `` / `readline FH` → `READLINE`, בהקשר הסובב. - `read`/`sysread` → `READ`; `getc FH` → `GETC`. - `close FH`, `eof FH`, `binmode FH`, `seek`, `tell`, `fileno`, `open FH, ...` → הוו באותיות רישיות המתאים כאשר הוא מוגדר. הערה על `STDERR`: כאשר `STDERR` קשור, ה־`PRINT` שלו הוא מה שמנפיק אזהרות והודעות שגיאה. זמן הריצה משבית את ה־tie למשך אותה קריאה, כך שתוכלו לבצע `warn` מתוך `PRINT` בלי לעורר רקורסיה אינסופית. ## מחלקה מינימלית ברת־קיימא אין מתודת חובה יחידה מעבר ל־`TIEHANDLE` - אתם מממשים את כל הפעולות שהמטפל יקבל. מטפל לפלט בלבד זקוק ל־`TIEHANDLE` בתוספת `PRINT` (ובדרך כלל `PRINTF`). מטפל לקלט בלבד זקוק ל־`TIEHANDLE` בתוספת `READLINE` (ואולי `GETC` / `READ`). פעולות שהוו שלהן חסר מתות בנקודת השימוש, ולכן הגדירו בדיוק את הקבוצה שהקוראים שלכם מפעילים. ## הדרך הקלה: ירושה מ־`Tie::StdHandle` `Tie::StdHandle` (מסופק בתוך `Tie::Handle`) קושר מטפל אל מטפל בסיסי אמיתי: ה־`OPEN` שלו פותח קובץ ממשי וווי הקלט/פלט מעבירים אליו. ירשו ממנו ועקפו רק את הפעולות שאתם רוצים ליירט: ```perl package Doubler { use Tie::StdHandle; our @ISA = ('Tie::StdHandle'); sub READLINE { my $self = shift; my $line = $self->SUPER::READLINE; return defined $line ? $line . $line : undef; # echo each line twice } } my $data = "a\nb\n"; tie *DUP, 'Doubler'; tied(*DUP)->OPEN('<', \$data); print while defined($_ = ); # a # a # b # b ``` `READLINE` קורא כלפי מעלה אל מחלקת הבסיס עבור השורה הבאה האמיתית, ואז מכפיל אותה; כל פעולה אחרת זורמת דרך `Tie::StdHandle` ללא שינוי. `Tie::Handle` (ההורה) הוא הבסיס המופשט שמתעד את הממשק ומספק `PRINT`/`PRINTF` ברירת מחדל באמצעות `WRITE`; `Tie::StdHandle` הוא הקונקרטי, המוכן לשימוש. ## ראו גם - [`tie`](../../p5/core/perlfunc/tie.md) - המובנה ותפריט המתודות המלא של המטפל - [`tied`](../../p5/core/perlfunc/tied.md) - הדרך היחידה להגיע אל מתודות שאינן קלט/פלט של מחלקת מטפל, כמו `buffer` למעלה - [`print`](../../p5/core/perlfunc/print.md) ו־[`printf`](../../p5/core/perlfunc/printf.md) - המובנים שמאחורי `PRINT` ו־`PRINTF` - [`readline`](../../p5/core/perlfunc/readline.md) - העמוד שלו מתעד את חוזה ההחזרה הסקלרי/רשימה ש־`READLINE` חייב לכבד - [סקלרים קשורים](scalars.md) - סוג ה־tie הפשוט ביותר, חימום טוב לקראת ממשק המטפל - `Tie::Handle` - מודול מחלקת הבסיס; `Tie::StdHandle` הוא הגרסה הקונקרטית