有没有办法在Perl脚本中的当前位置之前访问(打印输出)子+模块列表到任意深度的子调用?
我需要更改一些Perl模块(.pm).工作流通过cgi脚本从网页启动,通过在我需要使用数据的模块中结束的几个模块/对象传递输入.在某个地方,数据发生了变化,我需要找出原因.
您可以使用Devel :: StackTrace.
use Devel::StackTrace; my $trace = Devel::StackTrace->new; print $trace->as_string; # like carp
它的行为类似于Carp的踪迹,但您可以更好地控制帧.
一个问题是引用是字符串化的,如果引用的值发生变化,您将看不到它.但是,你可以用PadWalker来打印一些东西来打印出完整的数据(尽管这会很大).
Carp::longmess
会做你想做的,这是标准的.
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 ';
我想出了这个子(现在有可选的祝福'动作!)
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"; }
还有Carp::confess
和Carp::cluck
.