代码之家  ›  专栏  ›  技术社区  ›  slashmais

如何在Perl中获取调用堆栈列表?

  •  57
  • slashmais  · 技术社区  · 16 年前

    是否有一种方法可以访问(用于打印)Sub+模块的列表,以访问Perl脚本中当前位置之前任意深度的子调用?

    我需要更改一些Perl模块(.pm)。工作流是通过CGI脚本从网页启动的,通过几个模块/对象传递输入,这些模块/对象以我需要使用数据的模块结尾。沿着这条线的某个地方,数据发生了变化,我需要找出在哪里。

    6 回复  |  直到 7 年前
        1
  •  59
  •   Ovid    16 年前

    你可以使用 Devel::StackTrace .

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

    它的行为类似于鲤鱼的踪迹,但您可以对帧进行更多的控制。

    一个问题是引用被串化,如果引用的值改变了,您将看不到它。不过,你可以用 PadWalker 打印出完整的数据(尽管这将是巨大的)。

        2
  •  18
  •   Leon Timmermans    16 年前

    caller 可以做到这一点,尽管你可能需要更多的信息。

        3
  •  18
  •   community wiki 4 revs, 2 users 99% Axeman    14 年前

    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;
    }
    
        4
  •  16
  •   jkramer    16 年前

    还有 Carp::confess Carp::cluck .

        5
  •  14
  •   Thariama    7 年前

    这个代码工作 没有任何附加模块 . 只要在需要的地方包括它。

    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";
    }
    
        6
  •  3
  •   user2291758    10 年前

    更漂亮的是: Devel::PrettyTrace

    use Devel::PrettyTrace;
    bt;