Perl: How can I call object methods inside END {} without warning?

两盒软妹~` 提交于 2019-12-04 14:10:02
daxim

You most likely want DESTROY instead of END. See also the section on destructors in perltoot.

package JustTesting;
use strict;
use warnings;

sub new {
    my $self = {};
    bless($self, shift);
    return $self;
}

sub goodbye {
    print "Goodbye.\n";
}

sub DESTROY {
    my ($self) = @_;
    $self->goodbye()
};


package main;
{
    say "entering scope";
    my $this = JustTesting->new();
    say "leaving scope";
}
say "left scope";

Output:

entering scope
leaving scope
Goodbye.
left scope
draegtun

Just for reference to future readers I've attached a Moose version of daxim's correct answer.

use 5.012;
use warnings;

{
    package JustTesting;
    use Moose;
    use namespace::clean -except => 'meta';

    sub goodbye { say "Goodbye." }

    sub DEMOLISH {
        my ($self) = @_;
        $self->goodbye;
    }
}

{
    say "entering scope";
    my $this = JustTesting->new();
    say "leaving scope"; 
}

say "left scope";

Note the use of the DEMOLISH subroutine for the destructor.

NB. You will find that DESTROY still works but DEMOLISH is the correct Moosey way of doing it.

/I3az/

First, see my() Scoped Variable in Nested Subroutines for an explanation.

Second, I think you should either use DESTROY or a helper class depending on what you are trying to achieve.

The reason for the warning is because even though it doesn't look like it, to perl an END block is equivalent to the declaration of a regular (named) sub, and the behavior of a named sub declared inside of another sub isn't what you want -- $self inside the END block will be bound to $self in sub new the first time that new is called, and it will continue to see that same value -- the very first instance created -- for the rest of the life of your program. The first instance will have a reference held by the END block and won't be destroyed until the end of the program, and any later instances won't have that END block called on them at all.

Unlike named subs, anonymous subs don't have this problem because they're re-constructed every time their definition is encountered, so any variables they close over are bound as late as possible, and the values you actually want are captured.

This is a pretty long explanation when others have already told you that what you want is DESTROY instead, but I thought you might like to know what's actually happening with the code you wrote.

By the time the END block is called, $cleanup has already been deallocated. To do any work with a variable, you should use a destructor instead.

See "destructors" at perldoc perltoot.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!