# Filehandles με tie Ένα filehandle με tie δρομολογεί εκ νέου το I/O όπως ένα βαθμωτό με tie δρομολογεί εκ νέου τις αναγνώσεις και τις εγγραφές. Εκτυπώστε σε αυτό και τρέχει το δικό σας `PRINT`· διαβάστε μια γραμμή και τρέχει το δικό σας `READLINE`. Οι κλασικές χρήσεις είναι η ανακατεύθυνση της εξόδου κάπου ασυνήθιστα (σε μια συμβολοσειρά, μέσα από δίκτυο, μέσα από ένα φίλτρο) και η ενσωμάτωση της Perl σε ένα πρόγραμμα-ξενιστή που χρειάζεται ειδικό χειρισμό των `STDOUT` και `STDERR`. Η διεπαφή είναι μεγαλύτερη από τις άλλες αλλά κατά κύριο λόγο προαιρετική: υλοποιείτε μόνο τις λειτουργίες που θα λάβει στην πραγματικότητα το handle. Το πλήρες μενού βρίσκεται στη σελίδα αναφοράς του [`tie`](../../p5/core/perlfunc/tie.md)· αυτό το κεφάλαιο φτιάχνει μια κλάση και εξηγεί τα hooks και τον χρονισμό τους. ## Μια πλήρης κλάση Ένα handle μόνο για εγγραφή που συγκεντρώνει σε μια συμβολοσειρά οτιδήποτε εκτυπώνεται σε αυτό: ```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), όχι μέσω κάποιας λειτουργίας I/O - αυτός είναι ο τυπικός τρόπος με τον οποίο μια κλάση tie εκθέτει λειτουργίες χωρίς σύνταξη filehandle. ## Δέσιμο με tie του glob, όχι του βαθμωτού Το πρώτο όρισμα στο [`tie`](../../p5/core/perlfunc/tie.md) για ένα handle πρέπει να είναι ένα glob - ξεκινά με αστερίσκο: - Για να δέσετε με tie ένα κατονομασμένο handle: `tie *OUT, 'Collector'`. - Για να δέσετε με tie ένα handle που κρατείται σε ένα βαθμωτό `$fh`: `tie *$fh, 'Collector'`. Το να γράψετε `tie $fh, ...` δένει το *βαθμωτό* `$fh`, όχι το handle μέσα του - ένα συνηθισμένο και μπερδευτικό λάθος. ## Το συμβόλαιο των μεθόδων `TIEHANDLE classname, LIST` : Ο κατασκευαστής· επιστρέφει μια blessed αναφορά οποιουδήποτε είδους. Μπορεί να κρατά όποια εσωτερική κατάσταση χρειάζεται το handle. `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) - την ακατέργαστη, προσανατολισμένη σε ενταμιευτή εγγραφή, διακριτή από το `PRINT`. `READLINE this` : Στηρίζει τα `<$fh>` και [`readline`](../../p5/core/perlfunc/readline.md). Σε βαθμωτό περιβάλλον επιστρέψτε την επόμενη γραμμή ή `undef` στο τέλος της εισόδου· σε περιβάλλον λίστας επιστρέψτε όλες τις υπόλοιπες γραμμές ή μια κενή λίστα. Οι επιστρεφόμενες συμβολοσειρές πρέπει να περιλαμβάνουν τον διαχωριστή εγγραφής εισόδου `$/`, ώστε να ταιριάζουν με ό,τι σας δίνει ένα πραγματικό handle. `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` : Στηρίζουν τις αντίστοιχες ενσωματωμένες όταν χρησιμοποιούνται πάνω στο handle. Υλοποιήστε εκείνες που έχουν νόημα για τον υποκείμενο αποθηκευτικό χώρο σας και αφήστε τις υπόλοιπες απ” έξω. `DESTROY this` / `UNTIE this` : Προαιρετικός καθαρισμός, ταυτόσημος σε ρόλο με τους άλλους τύπους tie. Μια κλάση handle συχνά κλείνει εδώ τον υποκείμενο πόρο της. ## Χρονισμός κλήσεων - `print FH @list` και `say FH @list` → `PRINT`. Το `say` επιπλέον εντοπίζει τοπικά το `$\` σε `"\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, ...` → το αντίστοιχο hook με κεφαλαία όταν είναι ορισμένο. Μια σημείωση για το `STDERR`: όταν το `STDERR` είναι δεμένο με tie, το `PRINT` του είναι αυτό που εκδίδει τις προειδοποιήσεις και τα μηνύματα σφαλμάτων. Ο χρόνος εκτέλεσης απενεργοποιεί το tie για τη διάρκεια εκείνης της κλήσης, οπότε μπορείτε να καλέσετε `warn` μέσα από το `PRINT` χωρίς να πυροδοτήσετε άπειρη αναδρομή. ## Ελάχιστη βιώσιμη κλάση Δεν υπάρχει καμία μεμονωμένη υποχρεωτική μέθοδος πέρα από το `TIEHANDLE` - υλοποιείτε όποιες λειτουργίες θα λάβει το handle. Ένα handle μόνο για έξοδο χρειάζεται το `TIEHANDLE` συν το `PRINT` (και συνήθως το `PRINTF`). Ένα handle μόνο για είσοδο χρειάζεται το `TIEHANDLE` συν το `READLINE` (και ίσως το `GETC` / `READ`). Οι λειτουργίες των οποίων το hook λείπει πεθαίνουν στο σημείο χρήσης, οπότε ορίστε ακριβώς το σύνολο που χρησιμοποιούν οι καλούντές σας. ## Ο εύκολος τρόπος: κληρονομήστε από το `Tie::StdHandle` Το `Tie::StdHandle` (που συνοδεύει το `Tie::Handle`) δένει ένα handle πάνω σε ένα πραγματικό υποκείμενο: το `OPEN` του ανοίγει ένα πραγματικό αρχείο και τα hooks I/O προωθούν σε αυτό. Κληρονομήστε από αυτό και υπερκαλύψτε μόνο τις λειτουργίες που θέλετε να υποκλέψετε: ```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) - η ενσωματωμένη και το πλήρες μενού μεθόδων handle - [`tied`](../../p5/core/perlfunc/tied.md) - ο μόνος τρόπος να προσεγγίσετε τις μη-I/O μεθόδους μιας κλάσης handle, όπως το `buffer` παραπάνω - [`print`](../../p5/core/perlfunc/print.md) και [`printf`](../../p5/core/perlfunc/printf.md) - οι ενσωματωμένες πίσω από τα `PRINT` και `PRINTF` - [`readline`](../../p5/core/perlfunc/readline.md) - η σελίδα του τεκμηριώνει το συμβόλαιο επιστροφής βαθμωτού/λίστας που πρέπει να τιμά το `READLINE` - [Βαθμωτά με tie](scalars.md) - ο απλούστερος τύπος tie, ένα καλό προθέρμασμα για τη διεπαφή handle - `Tie::Handle` - το άρθρωμα της βασικής κλάσης· το `Tie::StdHandle` είναι η συγκεκριμένη εκδοχή