开发者

OO-Perl Aliasing Class Attributes

开发者 https://www.devze.com 2023-01-19 14:49 出处:网络
I have amodule that I\'m working on. I am setting up a few 开发者_运维问答attributes like this:

I have a module that I'm working on. I am setting up a few 开发者_运维问答attributes like this:

$self->{FOO};
$self->{BAR};
$self->{FOOBAR};

And, I want to use AUTOLOAD to help create methods for accessing these attributes. For example, $foo->Bar() returns the value of $self->{BAR}. No problem. Everything is standard.

Now, I want to create alias Methods. For example, if someone says $obj->Fu();, I'll return $self->{FOO}. What I'd like to do is create a $self->{FU} that points to the same memory location as $self->{FOO}. That way, when I set the value of $self->{FOO}, $self-{FU} is also set. This way, I don't have to make all sorts of changes in the way AUTOLOAD works or remember to set $self->{FU} whenever I set $self->{FOO}.

Any easy way of doing this?


Yes, use Moose, rather than attempting to make explicit mapping between hash keys. Writing your own accessors, or using AUTOLOAD, is not necessary and has a much higher chance of error:

package MyClass;

use Moose;
use MooseX::Aliases;

has foo => (
    is => 'rw', isa => 'Str',
    alias => 'fu',
);
has bar => (
    is => 'rw', isa => 'Str',
);
__PACKAGE__->meta->make_immutable;
no Moose;
1;

package main;
use strict;
use warnings;
use MyClass;
my $obj = MyClass->new;
$obj->foo("value");
$obj->fu("a new value");

# prints "foo has the value 'a new value'"
print "foo has the value '", $obj->foo, "'\n";


I would recommend Moose over what you're doing, but the easiest way to accomplish what you're asking is probably this:

sub Fu { shift->Foo(@_) }

This way, it doesn't matter if Foo is autoloaded or not.


The non-Moose solution is to just create an alias in the symbol table. It's not a common thing to do, and I suspect that whatever you are trying to do has a better way, Moose or otherwise. Don't use any of this if you can avoid it with a better design or interface, which are often the superior solutions to things like this.

In this AUTOLOAD routine, I look at a %Aliases hash to figure out other methods else I have to define. When I have aliases, I make proper aliases in the symbol table. It's a bit ugly, but it avoids adding another actual method in the call stack:

#!perl

use 5.010;

{
package SomeClass;
use Carp;
use vars qw($AUTOLOAD);

sub new {
    return bless { 
        map { $_, undef } qw(FOO BAR FOOBAR)
        }, $_[0];
    };

my %Aliases = (
    FOO => [ qw(fu) ],
    );

sub AUTOLOAD {
    our $method = $AUTOLOAD;
    $method =~ s/.*:://;

    carp "Autoloading $method";

    {
    no strict 'refs';
    *{"$method"} = sub { 
        @_ > 1 
                ? 
            $_[0]->{"\U$method"} = $_[1]
                :
            $_[0]->{"\U$method"}
        };

    foreach my $alias ( @{ $Aliases{"\U$method"} } ) {
        *{"$alias"} = *{"$method"};
        }

    goto &{"$method"};
    }

    }

sub DESTROY { 1 }
}

my $object = SomeClass->new;

$object->foo(5);

say "Foo is now ",   $object->foo;
say "Foo is now ",   $object->foo(9);
say "Fu is now ",    $object->fu;
say "Fu is set to ", $object->fu(17);
say "Foo is now ",   $object->foo;

Now foo and fu access the same thing:

Foo is now 5
Foo is now 9
Fu is now 9
Fu is set to 17
Foo is now 17
0

精彩评论

暂无评论...
验证码 换一张
取 消