Phasers: BEGIN, UNITCHECK, CHECK, INIT, END#
Πέντε ειδικά ονομασμένα μπλοκ επιτρέπουν στον κώδικα να συνδεθεί με τις μεταβάσεις που κάνει ένα πρόγραμμα ανάμεσα στο να μεταγλωττίζεται και στο να εκτελείται. Μοιάζουν με υπορουτίνες αλλά δεν είναι: μπορείτε να γράψετε πολλά από το καθένα, κανένα δεν έχει καλέσιμο όνομα, και το καθένα πυροδοτείται αυτόματα στη δική του στιγμή.
BEGIN { ... } # during compilation, as soon as defined
UNITCHECK { ... } # right after this compilation unit is compiled
CHECK { ... } # after the whole program is compiled
INIT { ... } # just before the runtime begins
END { ... } # just before the interpreter exits
Το πρόθεμα sub (sub BEGIN { ... }) γίνεται αποδεκτό αλλά δεν προσθέτει τίποτα και αποθαρρύνεται. Αυτά είναι μπλοκ, όχι ονομασμένες υπορουτίνες· δεν μπορείτε να τα καλέσετε, μόνο να τα αφήσετε να πυροδοτηθούν.
Πότε εκτελείται το καθένα#
Ένα πρόγραμμα Perl ζει σε δύο φάσεις: μια φάση μεταγλώττισης που αναλύει τον πηγαίο κώδικα σε μια εσωτερική μορφή, και μια φάση εκτέλεσης που τον εκτελεί. Οι phasers σημαδεύουν το όριο.
Το
BEGINεκτελείται τη στιγμή που αναλύεται η αγκύλη κλεισίματός του, προτού καν διαβαστεί το υπόλοιπο του αρχείου. Έτσι λειτουργεί ηuse: έναuseείναι μιαrequireτυλιγμένη σεBEGINσυνimport, οπότε τα εισαγόμενα ονόματα υπάρχουν για τον κώδικα που ακολουθεί. Μόλις εκτελεστεί έναBEGIN, γίνεται απροσδιόριστο και η μνήμη του ανακτάται.Το
UNITCHECKεκτελείται μόλις η μονάδα μεταγλώττισης που το περιέχει ολοκληρώσει τη μεταγλώττισή της. Μια μονάδα είναι το κύριο πρόγραμμα, ένα άρθρωμα που φορτώνεται μεrequire, ένα stringeval, έναdoFILE, ή κώδικας που μεταγλωττίζεται από την κατασκευή regex(?{ }). Επειδή οι μονάδες ολοκληρώνουν τη μεταγλώττισή τους σε διαφορετικές στιγμές, τοUNITCHECKείναι ο μόνος phaser του οποίου ο χρονισμός παρακολουθεί το μεμονωμένο αρχείο και όχι το πρόγραμμα ως σύνολο.Το
CHECKεκτελείται μία φορά, αφού τελειώσει η αρχική φάση μεταγλώττισης ολόκληρου του προγράμματος και πριν ξεκινήσει η φάση εκτέλεσης.Το
INITεκτελείται μία φορά, λίγο πριν αρχίσει η φάση εκτέλεσης, μετά από όλα τα μπλοκCHECK.Το
ENDεκτελείται μία φορά, όσο πιο αργά γίνεται: αφού έχει τελειώσει το πρόγραμμα (συμπεριλαμβανομένου του μετά από μιαdie), λίγο πριν εξέλθει ο διερμηνευτής.
Τα BEGIN και UNITCHECK είναι δεμένα με την ανάλυση, όχι με τη φάση του διερμηνευτή, οπότε μπορούν να πυροδοτηθούν κατά τη διάρκεια οποιασδήποτε φάσης: ένα string eval κατά τον χρόνο εκτέλεσης εξακολουθεί να μεταγλωττίζει το σώμα του, και κάθε BEGIN ή UNITCHECK μέσα του εκτελείται εκεί και τότε. Τα CHECK και INIT, αντιθέτως, σημαδεύουν το εφάπαξ όριο μεταγλώττισης/εκτέλεσης του κύριου προγράμματος.
Πολλαπλότητα και σειρά εκτέλεσης#
Μπορείτε να γράψετε οποιονδήποτε αριθμό από το κάθε μπλοκ. Όλα εκτελούνται, με καθορισμένη σειρά:
BEGIN: first in, first out (FIFO) όπως συναντώνται κατά τη μεταγλώττιση. Το πρώτοBEGINστη σειρά του πηγαίου κώδικα εκτελείται πρώτο.UNITCHECK: last in, first out (LIFO) μέσα σε κάθε μονάδα, αφού μεταγλωττιστεί αυτή η μονάδα.CHECK: LIFO, μετά από όλη τη μεταγλώττιση.INIT: FIFO, λίγο πριν τον χρόνο εκτέλεσης.END: LIFO κατά την έξοδο. Το τελευταίοENDπου ορίζεται είναι το πρώτο που εκτελείται.
Η διδακτική περίπτωση είναι ένα αρχείο που αναμειγνύει συνηθισμένες εντολές με τα και τα πέντε είδη μπλοκ. Τα μπλοκ δεν εκτελούνται εκεί όπου είναι γραμμένα· εκτελούνται στη φάση τους, με τη σειρά τους ανά φάση, ενώ οι συνηθισμένες εντολές εκτελούνται ενδιάμεσα κατά τον χρόνο εκτέλεσης. Εννοιολογικά, για ένα μεμονωμένο αρχείο:
1. BEGIN blocks -- FIFO, during compilation
2. UNITCHECK blocks -- LIFO, after this unit compiles
3. CHECK blocks -- LIFO, after all compilation
4. INIT blocks -- FIFO, just before runtime
5. ordinary code -- run phase, in source order
6. END blocks -- LIFO, at exit
Έτσι τα BEGIN και UNITCHECK εκτελούνται πριν από οποιοδήποτε CHECK· το CHECK εκτελείται πριν το INIT· το INIT εκτελείται πριν την πρώτη γραμμή συνηθισμένου κώδικα· και κάθε END εκτελείται μετά την τελευταία. Μέσα στα BEGIN και INIT, τα νωρίτερα γραμμένα μπλοκ εκτελούνται νωρίτερα· μέσα στα UNITCHECK, CHECK και END, τα αργότερα γραμμένα μπλοκ εκτελούνται νωρίτερα.
Τα μπλοκ END αναλυτικά#
Το END είναι ο phaser καθαρισμού. Εκτελείται με LIFO ώστε η αποδόμηση να ξετυλίγεται με την αντίστροφη σειρά της εγκατάστασης, όπως το περιμένουν οι εμφωλευμένοι πόροι.
Μέσα σε ένα μπλοκ END, το $? κρατά την τιμή που το πρόγραμμα πρόκειται να περάσει στην exit. Μπορείτε να το διαβάσετε για να μάθετε πώς τελειώνει το πρόγραμμα, και μπορείτε να του αναθέσετε τιμή για να αλλάξετε τον κωδικό εξόδου:
END {
$? = 0 if $? == 42; # rewrite one exit code on the way out
}
Προσέξτε μην αλλοιώσετε το $? κατά λάθος. Η εκτέλεση οτιδήποτε μέσω της system μέσα σε ένα μπλοκ END αντικαθιστά το $? με την κατάσταση του παιδιού, που στη συνέχεια γίνεται ο κωδικός εξόδου του προγράμματος εκτός αν το αποθηκεύσετε και το επαναφέρετε.
Τα μπλοκ END δεν εκτελούνται σε αρκετές περιπτώσεις:
Υπό τον διακόπτη
-c(έλεγχος σύνταξης μόνο μεταγλώττισης). Ο κύριος κώδικας δεν εκτελείται, ούτε και τα μπλοκEND.Όταν η μεταγλώττιση αποτυγχάνει. Ένα πρόγραμμα που δεν μεταγλωττίζεται δεν φτάνει ποτέ στο σημείο όπου θα πυροδοτούνταν τα μπλοκ
END.Όταν η διεργασία αντικαθιστά τον εαυτό της με
exec. Η εικόνα έχει χαθεί· δεν απομένει τίποτα για να εκτελέσει το μπλοκ.Όταν η διεργασία τερματίζεται από ένα μοιραίο σήμα που δεν παγιδεύετε. Πιάστε το σήμα μόνοι σας (μέσω
%SIG) αν χρειάζεται να εκτελεστεί ο καθαρισμός.
Ένα μπλοκ END που δημιουργείται μέσα σε ένα string eval δεν εκτελείται όταν τελειώνει αυτό το eval. Καταχωρείται όπως κάθε άλλο μπλοκ END του πακέτου του και εκτελείται με σειρά LIFO λίγο πριν εξέλθει ο διερμηνευτής.
Το ${^GLOBAL_PHASE} και οι φάσεις#
Η μεταβλητή μόνο για ανάγνωση ${^GLOBAL_PHASE} ονομάζει την τρέχουσα φάση του διερμηνευτή. Οι τιμές της επιτρέπουν σε κώδικα που εκτελείται σε περισσότερες από μία φάσεις να βρει πού βρίσκεται. Κατά τη διάρκεια ενός μπλοκ CHECK διαβάζεται CHECK· κατά το INIT, INIT· κατά τον συνηθισμένο κώδικα χρόνου εκτέλεσης, RUN· κατά τη διάρκεια ενός μπλοκ END, END. Δείτε το ${^GLOBAL_PHASE} για την πλήρη λίστα τιμών και τη χρονογραμμή των φάσεων.
Μπλοκ defer#
Ένα μπλοκ defer είναι ο μικρής κλίμακας ξάδελφος του END. Εκτελείται όταν εξέρχεται η περικλείουσα εμβέλεια μπλοκ, για οποιονδήποτε λόγο, αντί όταν εξέρχεται ολόκληρο το πρόγραμμα. Καταφύγετε στο defer για να ζευγαρώσετε την απόκτηση με την αποδέσμευση μέσα σε μια υπορουτίνα ή βρόχο· καταφύγετε στο END για αποδόμηση σε επίπεδο διεργασίας που πρέπει να γίνει μία φορά, στο τέλος τέλος.
Δείτε επίσης#
BEGINκαιuse- τοuseείναι μια φόρτωση-και-εισαγωγή τυλιγμένη σεBEGIN· ο πιο συνηθισμένος λόγος για να ενδιαφέρεστε για τον χρονισμό της φάσης μεταγλώττισης.${^GLOBAL_PHASE}- διαβάστε την τρέχουσα φάση από μέσα σε οποιοδήποτε μπλοκ για να μάθετε πού βρίσκεστε.defer- καθαρισμός με εμβέλεια μπλοκ, το σωστό εργαλείο όταν η εμβέλεια τουENDσε όλο το πρόγραμμα είναι υπερβολικά ευρεία.$?- η κατάσταση εξόδου που ένα μπλοκENDμπορεί να διαβάσει και να ξαναγράψει.%SIG- παγιδεύστε τα σήματα που διαφορετικά θα παρέκαμπταν εντελώς τα μπλοκEND.exit- αυτό λίγο πριν το οποίο εκτελούνται τα μπλοκEND· η τιμή που φέρει είναι το$?που βλέπει ένα μπλοκEND.