POD: Typo in Autor-Abschnitt verbessert.
[kivitendo-erp.git] / SL / LXDebug.pm
index cedd5ba..40ec54c 100644 (file)
@@ -20,7 +20,7 @@ use constant STDERR_TARGET => 1;
 
 use Data::Dumper;
 use POSIX qw(strftime getpid);
-use Scalar::Util qw(blessed reftype);
+use Scalar::Util qw(blessed refaddr weaken);
 use Time::HiRes qw(gettimeofday tv_interval);
 use YAML;
 use SL::Request ();
@@ -157,20 +157,51 @@ sub warn {
   $self->message(WARN, $message);
 }
 
-sub _clone_for_dump {
-  my ($src) = @_;
-
-  return undef unless defined($src);
-  return $src->as_debug_info                                            if blessed($src) && $src->can('as_debug_info');
-  return [ map { _clone_for_dump($_) } @{ $src } ]                      if reftype($src) eq 'ARRAY';
-  return { map { ($_ => _clone_for_dump($src->{$_})) } keys %{ $src } } if reftype($src) eq 'HASH';
-  return "$src";
-}
-
 sub dump {
   my ($self, $level, $name, $variable, %options) = @_;
 
-  $variable  = _clone_for_dump($variable);
+  my %dumped;
+
+  my $clone_for_dump;
+  $clone_for_dump = sub {
+    my ($src) = @_;
+
+    return undef if !defined($src);
+
+    my $addr = refaddr($src);
+
+    return $dumped{$addr} if $dumped{$addr // ''};
+
+
+    if (blessed($src) && $src->can('as_debug_info')) {
+      $dumped{$addr} = $src->as_debug_info;
+
+    } elsif (ref($src) eq 'ARRAY') {
+      $dumped{$addr} = [];
+
+      foreach my $entry (@{ $src }) {
+        my $exists = !!$dumped{refaddr($entry) // ''};
+        push @{ $dumped{$addr} }, $clone_for_dump->($entry);
+
+        weaken($dumped{$addr}->[-1]) if $exists;
+
+      }
+
+    } elsif (ref($src) =~ m{^(?:HASH|Form|SL::.+)$}) {
+      $dumped{$addr} = {};
+
+      foreach my $key (keys %{ $src }) {
+        my $exists             = !!$dumped{refaddr($src->{$key}) // ''};
+        $dumped{$addr}->{$key} = $clone_for_dump->($src->{$key});
+
+        weaken($dumped{$addr}->{$key}) if $exists;
+      }
+    }
+
+    return $dumped{$addr} // "$src";
+  };
+
+  $variable  = $clone_for_dump->($variable);
   my $dumper = Data::Dumper->new([$variable]);
   $dumper->Sortkeys(1);
   $dumper->Indent(2);