Ροή ελέγχου · Εμβέλεια

caller#

Επιστρέφει πληροφορίες σχετικά με την υπορουτίνα, την eval ή την require που κάλεσε τον κώδικα που εκτελείται αυτή τη στιγμή.

Η caller διατρέχει τη στοίβα κλήσεων. Χωρίς όρισμα επιστρέφει μια σύντομη εγγραφή τριών στοιχείων που προσδιορίζει ποιος μας κάλεσε. Με ένα αριθμητικό όρισμα EXPR διατρέχει EXPR πλαίσια πιο πίσω και επιστρέφει μια εκτενέστερη εγγραφή έντεκα στοιχείων - τη μορφή που χρησιμοποιούν ο debugger, τα αρθρώματα ιχνηλάτησης στοίβας, καθώς και ο μηχανισμός των warn/die για να εμπλουτίζουν τα διαγνωστικά μηνύματα με πληροφορίες αρχείου και γραμμής. Τα πλαίσια XS είναι αόρατα στην caller· στη θέση τους εμφανίζεται το επόμενο πλαίσιο καθαρής Perl.

Σύνοψη#

caller
caller EXPR

Τι επιστρέφεται#

Σε βαθμωτό περιβάλλον, το όνομα του πακέτου του καλούντος, ή undef αν δεν υπάρχει καλών (δηλαδή βρισκόμαστε στο ανώτατο επίπεδο του αρχείου, εκτός από sub, eval ή require):

my $pkg = caller;

Σε περιβάλλον λίστας χωρίς όρισμα, τρία στοιχεία - το πακέτο, το αρχείο και ο αριθμός γραμμής του άμεσου καλούντος:

# 0         1          2
my ($package, $filename, $line) = caller;

Σε περιβάλλον λίστας με αριθμητικό όρισμα, έντεκα στοιχεία που περιγράφουν το πλαίσιο EXPR επίπεδα ψηλότερα. Το 0 είναι ο άμεσος καλών, το 1 είναι ο δικός του καλών, και ούτω καθεξής:

# 0         1          2      3            4
my ($package, $filename, $line, $subroutine, $hasargs,

#   5          6          7            8       9         10
    $wantarray, $evaltext, $is_require, $hints, $bitmask, $hinthash)
  = caller($i);

Τα έντεκα πεδία, με τη σειρά:

  • $package, $filename, $line - η τοποθεσία του σημείου κλήσης μέσα στον καλούντα εκείνου του πλαισίου. Οι ίδιες τρεις τιμές που επιστρέφει η σύντομη μορφή.

  • $subroutine - το πλήρως προσδιορισμένο όνομα της υπορουτίνας στην οποία ανήκει το πλαίσιο, π.χ. "Foo::bar". Για ένα πλαίσιο eval είναι η κυριολεκτική συμβολοσειρά "(eval)". Αν η υπορουτίνα έχει αφαιρεθεί από τον πίνακα συμβόλων μετά την κλήση, είναι "(unknown)".

  • $hasargs - αληθές αν ένας φρέσκος @_ εγκαταστάθηκε για το πλαίσιο. Ψευδές για πλαίσια eval και require.

  • $wantarray - το περιβάλλον στο οποίο κλήθηκε το πλαίσιο, όπως θα το είχε αναφέρει η wantarray: αληθές για λίστα, ορισμένο-αλλά-ψευδές ("") για βαθμωτό, undef για κενό (void).

  • $evaltext - για ένα πλαίσιο eval EXPR, το κείμενο πηγαίου κώδικα που μεταγλωττίστηκε. Undef για eval BLOCK και για μη-eval πλαίσια.

  • $is_require - αληθές αν το πλαίσιο δημιουργήθηκε από require ή use (κάθε use δημιουργεί ένα πλαίσιο require εμφωλευμένο μέσα σε ένα πλαίσιο eval EXPR).

  • $hints - η τιμή του $^H τη στιγμή που μεταγλωττίστηκε ο κώδικας του πλαισίου. Εσωτερικό· η διάταξη δεν είναι σταθερή μεταξύ εκδόσεων της Perl.

  • $bitmask - η τιμή του ${^WARNING_BITS} στο ίδιο σημείο. Επίσης εσωτερικό.

  • $hinthash - μια αναφορά στο hash %^H που καταγράφηκε κατά τη μεταγλώττιση, ή undef αν ήταν κενό. Μην την τροποποιείτε - η αναφορά δείχνει στο ζωντανό optree.

Καθολική κατάσταση που επηρεάζει#

  • @DB::args - ορίζεται ως παρενέργεια όταν η caller καλείται με όρισμα μέσα από το πακέτο DB. Η λίστα ορισμάτων του καλούντος ψευδωνυμοποιείται σε αυτόν τον πίνακα για χρήση από τον debugger. Δείτε Οριακές περιπτώσεις παρακάτω - αυτή είναι μια προσπάθεια βέλτιστης πρόθεσης και έχει αιχμηρές γωνίες.

  • $^H, ${^WARNING_BITS}, %^H - διαβάζονται από τη μεταγλωττισμένη κατάσταση του πλαισίου-στόχου για να συμπληρώσουν τα $hints, $bitmask, $hinthash.

Παραδείγματα#

Βρείτε το πακέτο του άμεσου καλούντος και αναφέρετε στο σωστό αρχείο καταγραφής:

sub log_for_caller {
    my $pkg = caller;
    warn "[$pkg] @_\n";
}

Παραγάγετε μια ετικέτα τοποθεσίας σε στιλ warn. Η caller επιστρέφει το όνομα αρχείου και τη γραμμή του σημείου κλήσης ένα πλαίσιο ψηλότερα, που είναι σχεδόν πάντα η πληροφορία που πραγματικά θέλετε σε ένα διαγνωστικό:

sub note {
    my (undef, $file, $line) = caller;
    print STDERR "note at $file line $line: @_\n";
}

Διατρέξτε ολόκληρη τη στοίβα. Επαναλάβετε την caller($i) μέχρι να επιστρέψει κενή λίστα:

sub stacktrace {
    my @frames;
    for (my $i = 0; my @f = caller($i); $i++) {
        push @frames, \@f;
    }
    return @frames;
}

Ανιχνεύστε αν η τρέχουσα υπορουτίνα κλήθηκε σε περιβάλλον λίστας, βαθμωτό ή κενό. Αυτό είναι η wantarray στο τρέχον επίπεδο, αλλά για το πλαίσιο κάποιου άλλου το προσεγγίζετε μέσω της caller:

sub describe_parent_context {
    my $wa = (caller(1))[5];
    return !defined $wa ? "void"
         :  $wa         ? "list"
         :                "scalar";
}

Διακρίνετε ένα πλαίσιο require/use από ένα κανονικό eval:

sub called_from_require {
    my @f = caller(1);
    return @f && $f[7];             # field 7 is $is_require
}

Αποτυπώστε ένα μεμονωμένο πλαίσιο όπως κάνει ο προεπιλεγμένος μορφοποιητής της die / του Carp - "at FILE line LINE":

sub location_tag {
    my $depth = shift // 0;
    my (undef, $file, $line) = caller($depth);
    return defined $file ? "at $file line $line" : "at top level";
}

Οριακές περιπτώσεις#

  • Βαθμωτό περιβάλλον, χωρίς καλούντα: στο ανώτατο επίπεδο ενός σεναρίου, η scalar caller επιστρέφει undef, ενώ η caller σε περιβάλλον λίστας επιστρέφει την κενή λίστα. Ένα κοινό ιδίωμα για το «εκτελούμαι με require ως άρθρωμα ή ως σενάριο;» είναι το caller() ? ... : ....

  • Τα πλαίσια XS παραλείπονται. Η caller αναφέρει μόνο πλαίσια καθαρής Perl. Αν μια υπορουτίνα καθαρής Perl κλήθηκε από μια υπορουτίνα XS η οποία με τη σειρά της κλήθηκε από άλλη υπορουτίνα καθαρής Perl, η caller(0) από την εσωτερική υπορουτίνα αναφέρει την εξωτερική υπορουτίνα καθαρής Perl - το στρώμα XS είναι αόρατο. Τα βάθη στοίβας που μετρώνται με την caller δεν περιλαμβάνουν επομένως διανομείς XS.

  • Τα πλαίσια eval δεν έχουν ορίσματα. Το $hasargs είναι ψευδές για πλαίσια eval και require, και το $subroutine είναι η κυριολεκτική τιμή "(eval)" - όχι το πακέτο του περιβάλλοντος κώδικα.

  • eval BLOCK έναντι eval EXPR. Και τα δύο δίνουν $subroutine eq "(eval)". Μόνο η eval EXPR συμπληρώνει το $evaltext· η eval BLOCK το αφήνει undef.

  • Η use δημιουργεί δύο πλαίσια. Μια εντολή use Foo μεταγλωττίζεται ως BEGIN { require Foo; Foo->import; }, ενώ η ίδια η require υλοποιείται ως eval EXPR. Η διατρέξιμη της στοίβας μέσα από μια γραμμή use βλέπει επομένως ένα πλαίσιο eval σημασμένο ως require μέσα σε ένα κανονικό πλαίσιο eval. Ελέγξτε το $is_require για να τα διακρίνετε.

  • Υπορουτίνες (unknown). Αν η υπορουτίνα που κατονομάζεται σε ένα πλαίσιο έχει διαγραφεί από τον πίνακα συμβόλων (επεμβάσεις στον πίνακα συμβόλων, delete $Foo::{bar}) μεταξύ της κλήσης και της caller, το $subroutine διαβάζεται ως "(unknown)".

  • Οι βρόχοι και τα μπλοκ try δεν αποτελούν πλαίσια. Τα while, for, foreach και try δεν δημιουργούν πλαίσια κλήσης. Η caller βλέπει μόνο κλήσεις υπορουτινών και eval.

  • Πλαίσια που αφαιρεί ο βελτιστοποιητής. Ο βελτιστοποιητής μπορεί να αφαιρέσει πλαίσια ουραίας κλήσης και παρόμοια προτού η caller μπορέσει να τα παρατηρήσει. Για caller(N) με N > 1, το πλαίσιο που λαμβάνετε δεν είναι εγγυημένα το πλαίσιο που περιμένατε. Μην κωδικοποιείτε το βάθος στοίβας ως φέρουσα σύμβαση.

  • Το @DB::args λειτουργεί με βέλτιστη πρόθεση. Συμπληρώνεται μόνο όταν η caller καλείται με όρισμα μέσα από το πακέτο DB. Οι τιμές είναι ψευδώνυμα προς τον @_ του πλαισίου-στόχου, όχι αντίγραφα - οπότε:

    • Οι μεταβολές που έχει ήδη κάνει το πλαίσιο στον @_ είναι ορατές· οι αρχικές τιμές κατά την κλήση δεν διατηρούνται.

    • Το shift @_ μέσα στο πλαίσιο συνήθως αναιρείται στο @DB::args, όμως τα pop @_, οι splices ή η λήψη αναφοράς στον @_ σπάνε αυτή τη συμπεριφορά.

    • Τα στοιχεία μπορεί να έχουν απελευθερωθεί και να έχουν επαναχρησιμοποιηθεί για άλλες τιμές μέχρι να τα διαβάσετε.

    • Παλιά κατάσταση από προηγούμενη κλήση της caller ενδέχεται να παραμένει στο @DB::args αν η τρέχουσα κλήση δεν προκάλεσε ανανέωση. Χρησιμοποιήστε το για backtraces και εμφάνιση στον debugger· μην βασίζεστε σε αυτό για τη λογική του προγράμματος.

  • Το $hinthash είναι ζωντανό. Η αναφορά hash στο πεδίο 10 δείχνει στο πραγματικό στιγμιότυπο %^H που έχει ψηθεί στο optree. Η τροποποίηση των περιεχομένων του μεταβάλλει την κατάσταση του μεταγλωττιστή. Διαβάστε το· μην το γράφετε.

  • Το όνομα αρχείου και η γραμμή μπορούν να επανεγγραφούν. Οι οδηγίες #line και οτιδήποτε άλλο αναγνωρίζει ο μηχανισμός «Plain Old Comments (Not!)» (δείτε perlsyn) αλλάζουν τις τιμές που αναφέρει η caller, ακριβώς όπως αλλάζουν τα __FILE__ και __LINE__.

Διαφορές από το upstream#

Πλήρως συμβατό με το upstream Perl 5.42.

Δείτε επίσης#

  • die - εγείρει εξαίρεση· το προεπιλεγμένο μήνυμά της χρησιμοποιεί τις ίδιες πληροφορίες αρχείου-και-γραμμής που εκθέτει η caller

  • eval - δημιουργεί πλαίσια που η caller σημαίνει με $subroutine eq "(eval)" και μπορεί να συμπληρώσει τα $evaltext / $is_require

  • wantarray - αναφέρει το περιβάλλον κλήσης του τρέχοντος πλαισίου· η ίδια τιμή εμφανίζεται ως πεδίο 5 της caller(N) για το πλαίσιο N επίπεδα ψηλότερα

  • $^H - bits υπόδειξης κατά τη μεταγλώττιση· εμφανίζονται ως πεδίο 8

  • %^H - hash υπόδειξης κατά τη μεταγλώττιση· εμφανίζεται ως πεδίο 10

  • ${^WARNING_BITS} - bitmask προειδοποιήσεων· εμφανίζεται ως πεδίο 9