72 votes

Comment puis-je obtenir une liste de la pile d'appels en Perl ?

Y a-t-il un moyen d'accéder (pour l'impression) à une liste de sous-modules + module à une profondeur arbitraire de sous-appels précédant la position actuelle dans un script Perl?

J'ai besoin de faire des modifications à certains modules Perl (.pm). Le flux de travail est initié à partir d'une page web via un cgi-script, passant des entrées à travers plusieurs modules/objets se terminant dans le module où j'ai besoin d'utiliser les données. À un moment donné, les données ont été modifiées et j'ai besoin de savoir où.

0 votes

Bien que cela ne réponde pas à votre question, cela pourrait vous aider à résoudre votre problème :-) Voici un article intéressant décrivant une façon de savoir qui modifie vos variables depuis Mark Dominus

68voto

Ovid Points 7256

Vous pouvez utiliser Devel::StackTrace.

use Devel::StackTrace;
my $trace = Devel::StackTrace->new;
print $trace->as_string; # comme carp

Cela fonctionne comme la trace de Carp, mais vous pouvez avoir plus de contrôle sur les frames.

Le seul problème est que les références sont transformées en chaînes de caractères et si une valeur référencée change, vous ne la verrez pas. Cependant, vous pourriez mettre en place quelques choses avec PadWalker pour imprimer toutes les données (ce serait énorme, cependant).

3 votes

Une alternative très utile : perl -d:Confess script.pl de Devel::Confess.

20voto

Axeman Points 24103

Carp::longmess fera ce que vous voulez, et c'est standard.

use Carp qw;
use Data::Dumper;
sub A { &B; }
sub B { &C; }
sub C { &D; }
sub D { &E; }

sub E { 
    # Uncomment below if you want to see the place in E
    # local $Carp::CarpLevel = -1; 
    my $mess = longmess();
    print Dumper( $mess );
}

A();
__END__
$VAR1 = ' at - line 14
    main::D called at - line 12
    main::C called at - line 10
    main::B called at - line 8
    main::A() called at - line 23
';

J'ai trouvé cette sous-routine (Maintenant avec option d'action de bénédiction!)

my $stack_frame_re = qr{
    ^                # Beginning of line
    \s*              # Any number of spaces
    ( [\w:]+ )       # Package + sub
    (?: [(] ( .*? ) [)] )? # Anything between two parens
    \s+              # At least one space
    called [ ] at    # "called" followed by a single space
    \s+ ( \S+ ) \s+  # Spaces surrounding at least one non-space character
    line [ ] (\d+)   # line designation
}x;

sub get_stack {
    my @lines = split /\s*\n\s*/, longmess;
    shift @lines;
    my @frames
        = map { 
              my ( $sub_name, $arg_str, $file, $line ) = /$stack_frame_re/;
              my $ref =  { sub_name => $sub_name
                         , args     => [ map { s/^'//; s/'$//; $_ } 
                                         split /\s*,\s*/, $arg_str 
                                       ]
                         , file     => $file
                         , line     => $line 
                         };
              bless $ref, $_[0] if @_;
              $ref
          } 
          @lines
       ;
    return wantarray ? @frames : \@frames;
}

1 votes

Longmess n'est plus une fonctionnalité documentée ou automatiquement exportée de Carp. Cependant : my $mess = carp(); fournira un comportement similaire mais non identique.

18voto

Leon Timmermans Points 23230

caller peut le faire, bien que vous puissiez souhaiter encore plus d'informations que cela.

16voto

jkramer Points 7271

Il y a aussi Carp::confess et Carp::cluck.

7voto

Pat Points 18943

Alors que cela ne répond pas à votre question, cela pourrait vous aider à résoudre votre problème :-)

Voici un article intéressant décrivant une façon de découvrir qui modifie vos variables de Mark Dominus

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X