向perl中的现有对象添加新方法 [英] Add new method to existing object in perl

查看:97
本文介绍了向perl中的现有对象添加新方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这个perl对象.实例化对象之后,我尝试在加载器方法中向对象添加一个新方法,然后可以在以后调用它.

I have this perl object. After the object is instantiated, I'm trying to add a new method to the object within a loader method, that can then be called later.

我已经尝试了很多没有用的东西.示例包括:

I've tried a whole bunch of stuff that hasn't worked. Examples include:

sub loader {
    my ($self) = @_;

    sub add_me {
        my ($self, $rec) = @_

        warn "yayyyyyy";
        return $rec;
    }

    #here are the things I've tried that dont work:
    # &{$self->{add_me}} = \&add_me;
    # \&{$self->{add_me}} = \&add_me;
    # assuming the class definition is in Holder::Class try to add it to symblol table
    # *{Holder::Class::add_me} = \&add_me;

}

之所以需要这样做,是因为我在代码中添加了一个钩子,使我的软件用户可以按需注入自己的子集来编辑数据结构.

The reason that I need to do this is I'm adding a hook in my code where the user of my software will have the ability to inject their own sub to edit a data structure as they will.

为此,他们将能够编辑仅包含一个子文件的辅助文件,并将有问题的数据结构传递进来,例如:

To do this, they will be able to edit a secondary file that will only contain one sub and get the data structure in question passed in, so something like:

sub inject_a_sub {
    my ($self, $rec) = @_;

    #do stuff to $rec

    return $rec;
}

然后在实例化我的原始对象后,检查上述文件是否存在,如果存在,请读取其内容并进行评估.最后,我想制作一个评估的代码,它只是我的对象的一个​​子方法.确切地说,我的对象已经在继承一个名为do_something的方法,我想让eval读取的子程序覆盖正在继承的do_something方法,以便从外部文件调用该子程序时运行.

then inside my original object upon its instantiation, I check to see if the above mentioned file exists, and if so read its contents and eval them. Lastly, I want to make the eval'd code which is just a sub, a method of my object. To be precise, my object is already inheriting a method called do_something and i want to make the sub read in by the eval override the do_something method being inherited so that when called the sub from the external file runs.

有一个奇怪的问题:/

这伤了我:(

欧比万基诺比,你是我唯一的希望!

Obi wan kenobi you're my only hope!

干杯!

推荐答案

如果您只想将功能附加到特定对象,并且不需要继承,则可以将代码ref存储在该对象中并对其进行调用. /p>

If you just want to attach functionality to a specific object, and don't need inheritance, you can store a code ref in the object and call it.

# Store the code in the object, putting it in its own
# nested hash to reduce the chance of collisions.
$obj->{__actions}{something} = sub { ... };

# Run the code
my @stuff = $obj->{__actions}{something}->(@args);

问题是,您需要检查$obj->{__actions}{something}是否包含代码引用.我建议围绕此过程包装一个方法.

Problem is, you need to check that $obj->{__actions}{something} contains a code reference. What I would suggest is to wrap a method around this procedure.

sub add_action {
    my($self, $action, $code) = @_;

    $self->{__actions}{$action} = $code;

    return;
}

sub take_action {
    my($self, $action, $args) = @_;

    my $code = $self->{__actions}{$action};
    return if !$code or ref $code ne 'CODE';

    return $code->(@$args);
}

$obj->add_action( "something", sub { ... } );
$obj->take_action( "something", \@args );


如果您已经知道要向其中注入方法的类名,请照常编写子例程,但使用完全限定的名称.


If you already know the class name you want to inject a method into, write the subroutine as normal but use the fully qualified name.

sub Some::Class::new_method {
    my $self = shift;

    ...
}

请注意,该子例程中的所有全局变量都将位于周围的包中,而不是Some :: Class中的 .如果要使用持久变量,请在子例程内使用state或在子例程外使用my.

Note that any globals inside that subroutine will be in the surrounding package, not in Some::Class. If you want persistent variables use state inside the subroutine or my outside the subroutine.

如果在编译时不知道名称,则必须将子例程注入到符号表中,因此您与最后一个例程很接近.

If you don't know the name at compile time, you'll have to inject the subroutine into the symbol table, so you were close with that last one.

sub inject_method {
    my($object, $method_name, $code_ref) = @_;

    # Get the class of the object
    my $class = ref $object;

    {
        # We need to use symbolic references.
        no strict 'refs';

        # Shove the code reference into the class' symbol table.
        *{$class.'::'.$method_name} = $code_ref;
    }

    return;
}

inject_method($obj, "new_method", sub { ... });

Perl中的方法与类而不是对象相关联.为了将方法分配给单个对象,您必须将该对象放入其自己的类中.与上述类似,但是您必须为每个实例创建一个子类.

Methods in Perl are associated with a class, not an object. In order to assign a method to a single object, you have to put that object into its own class. Similar to the above, but you have to create a subclass for every instance.

my $instance_class = "_SPECIAL_INSTANCE_CLASS_";
my $instance_class_increment = "AAAAAAAAAAAAAAAAAA";
sub inject_method_into_instance {
    my($object, $method_name, $code_ref) = @_;

    # Get the class of the object
    my $old_class = ref $object;

    # Get the special instance class and increment it.
    # Yes, incrementing works on strings.
    my $new_class = $instance_class . '::' . $instance_class_increment++;

    {
        # We need to use symbolic references.
        no strict 'refs';

        # Create its own subclass
        @{$new_class.'::ISA'} = ($old_class);

        # Shove the code reference into the class' symbol table.
        *{$new_class.'::'.$method_name} = $code_ref;

        # Rebless the object to its own subclass
        bless $object, $new_class;
    }

    return;
}

我遗漏了代码,通过检查实例的类是否匹配/^${instance_class}::/来检查实例是否已经进行了这种处理.我把它留给你练习.为每个对象创建一个新类并不便宜,而且会占用内存.

I left out the code to check whether or not the instance has already had this treatment by checking if its class matches /^${instance_class}::/. I leave that as an exercise for you. Creating a new class for every object is not cheap and will cost memory.

这样做有充分的理由,但它们是例外.您应该真正质疑您是否应该执行这种猴子补丁.通常,应避免远距离操作.

There are valid reasons to do this, but they are exceptional. You should really, really question whether you should be doing this sort of monkey patching. In general, action at a distance should be avoided.

您可以使用子类,委托或角色来完成相同的事情吗?

Can you accomplish the same thing using a subclass, delegation or role?

已经存在Perl OO系统,它将为您做更多的事情.您应该使用一个. Moose ,Moo(通过鼠标都可以将角色添加到实例.

There already exist Perl OO systems which will do this for you and much much more. You should be using one. Moose, Moo (via Role::Tiny) and Mouse can all add roles to an instance.

这篇关于向perl中的现有对象添加新方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆