in reply to Avoiding circular references
Note that circular references are not intrinsically bad, only when they become memory leaks are they bad. There are a couple of approaches to handling circular references:
Personally, I prefer weak references. In this case, if your object of type Helper will only exist during the lifetime of the object of type A, then the following is one approach where the Helper object is a "child" of the A object, and a weak reference works fine, because the anonymous sub isn't closing over $self. Weakening $self->{parent} in Helper is fine, because we know the parent object will exist for the entire lifetime of the Helper, and we want the helper to be destroyed when the parent is destroyed.
use strict; use warnings; use Devel::Cycle; package A; sub new { my ($class, $href) = @_; my $self = { dbi => $$href{dbi} }; $self->{helper_child} = Helper->new( parent => $self, helper_function => sub { my $parent = shift; $parent->this_is_in_A(@_); }, ); bless $self, $class; } sub do_something { my $self = shift; $self->{helper_child}->do_helper(); } sub this_is_in_A { my ($self, $arg) = @_; print "this_is_in_A, arg: $arg, dbi is $self->{dbi}\n"; } sub DESTROY { print shift."->DESTROY\n" } package Helper; use Scalar::Util qw/weaken/; sub new { my $class = shift; my $self = { @_ }; weaken( $self->{parent} ); bless $self, $class; } sub do_helper { my $self = shift; $self->{helper_function}->($self->{parent}, "param from Helper"); } sub DESTROY { print shift."->DESTROY\n" } package main; my $x = A->new( { dbi => "some dbi object" } ); $x->do_something(); $x->do_something(); find_cycle($x); print "undef'ing \$x\n"; $x = undef; print "End\n"; __END__ this_is_in_A, arg: param from Helper, dbi is some dbi object this_is_in_A, arg: param from Helper, dbi is some dbi object undef'ing $x A=HASH(0x55e36742fc88)->DESTROY Helper=HASH(0x55e36742fdc0)->DESTROY End
Update: Note that in sub do_helper, we could also have done $self->{helper_function}->($self, "param from Helper");, so that the helper_function is called as if it were a method on the Helper class.
|
|---|