Как я могу получить список стека вызовов в Perl?
есть ли способ получить доступ (для распечатки) к списку sub + модуля к произвольной глубине подзвонков, предшествующих текущей позиции в скрипте Perl?
Мне нужно внести изменения в некоторые модули Perl (. pm). рабочий процесс инициируется с веб-страницы через CGI-скрипт, передавая ввод через несколько модулей / объектов, заканчивающихся в модуле, где мне нужно использовать данные. Где-то по ходу дела данные изменились, и мне нужно выяснить, где.
7 ответов:
можно использовать Devel:: StackTrace.
use Devel::StackTrace; my $trace = Devel::StackTrace->new; print $trace->as_string; # like carpОн ведет себя, как след карповых, но вы можете получить больше контроля над кадрами.
одна проблема заключается в том, что ссылки строковые и если ссылочное значение изменяется, вы не увидите его. Тем не менее, вы можете на скорую руку некоторые вещи с PadWalker чтобы распечатать полные данные (это было бы огромным, хотя).
caller может сделать это, хотя вы можете хотеть даже больше информации, чем это.
Carp::longmessбудет делать то, что вы хотите, и это стандарт.use Carp qw<longmess>; 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 ';Я придумал эту суб (теперь с дополнительным благословляющим действием!)
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; }
этот код работает без каких-либо дополнительных модулей. Просто включите его там, где это необходимо.
my $i = 1; print STDERR "Stack Trace:\n"; while ( (my @call_details = (caller($i++))) ){ print STDERR $call_details[1].":".$call_details[2]." in function ".$call_details[3]."\n"; }
хотя это не ответ на ваш вопрос, это может помочь вам решить ваши проблемы :-)
вот интересная статья, описывающая один из способов, как выяснить, кто изменяет переменные Марк Доминус
тот, что красивее:Devel:: PrettyTrace
use Devel::PrettyTrace; bt;
Comments