Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

Adding functionality to an Object

by jeanluca (Deacon)
on Jul 13, 2006 at 08:50 UTC ( [id://560891]=perlquestion: print w/replies, xml ) Need Help??

jeanluca has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks

I was just wondering about the possibility to add new functionalities to an object. Like adding new subroutines!

Can this be done with perl object ?

ThnX
LuCa

Replies are listed 'Best First'.
Re: Adding functionality to an Object
by davorg (Chancellor) on Jul 13, 2006 at 08:58 UTC

    Yes. You can do that.

    The best way is probably to subclass the object and add your new methods to the subclass. But it's perfectly possible to add methods to an existing object. A method is just a subroutine that exists in a particular symbol table. You just have to switch to the correct package and define a new subroutine.

    --
    <http://dave.org.uk>

    "The first rule of Perl club is you do not talk about Perl club."
    -- Chip Salzenberg

      I would like to do this stuff at runtime. Is there documentation about this stuff ?

      LuCa

        In the first instance you might want to look at perlboot and perltoot as they both cover Inheritance.

        As to adding methods to a class at runtime, yes that is entirely possible (you will find a number of modules that do this in a sub AUTOLOAD,) but you might want to carefully review your design as it is probably not the best solution in the general case.

        However if you really insist on adding methods dynamically you can do something as simple as:

        package Foo; + sub new { my ( $class ) = @_; return bless {}, $class; } + package main; + use strict; + my $foo = Foo->new(); + *Foo::zub = sub { print "I'm zub!\n"; }; + $foo->zub();

        /J\

        If you want to do it at runtime then you'll need to fiddle around with the "victim" object's symbol table.

        One example of doing this is in Symbol::Approx::Sub which inserts an AUTOLOAD function into its caller's symbol table. I wrote an article about how that works. You might find that useful.

        There are no doubt plenty of other modules on CPAN that do similar things. I'd guess that the Acme:: namespace would be a good place to start looking.

        --
        <http://dave.org.uk>

        "The first rule of Perl club is you do not talk about Perl club."
        -- Chip Salzenberg

        I would like to do this stuff on runtime. Is there documentation about this stuff ?

        If you are designing the objects, then look at Class::Prototyped.

        my $cp = Class::Prototyped->new(); my $mirror = $cp->reflect(); $mirror->addSlots( field1 => 'foo', sub1 => sub { print "this is sub1 printing field1: '".$_[0]->field1."'\n"; }, ); $mirror->deleteSlot('sub1');

        There are others, too, like Class::Object or Class::Decorator that do things like this in various ways.

        If you didn't design the object, then you could use Class::Adapter to wrap the object while adding your own methods.

        As more of a hack, if you really need to do it on the fly, you can rebless the object into a dynamically generated subclass that has the methods you want. E.g.

        # Create an object of Some::Class my $obj = Some::Class->new(); $obj->foo(); # where foo() is a method of Some::Class # Create the new "class" by assigning @ISA and a method in the new nam +espace @Some::Class::Extended::ISA = qw/Some::Class/; *Some::Class::Extended::bar = sub { my $self = shift; print "Hello, Ba +r" }; # Rebless the object to the new class bless $obj, 'Some::Class::Extended'; $obj->foo; # From Some::Class $obj->bar; # From Some::Class::Extended

        -xdg

        Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

Re: Adding functionality to an Object
by broquaint (Abbot) on Jul 13, 2006 at 11:37 UTC
    If you're looking for a quick and dirty solution and you're working with your own (hash-based) objects this should do the trick:
    use strict; use warnings; use Test::More tests => 9; { package root; sub base { "do" } package foo; @foo::ISA = 'root'; sub new { bless {@_[1 .. $#_]}, $_[0] } sub hey { 'yo' } } sub add_method_to_class { my($cls, $name, $meth) = @_; no strict 'refs'; *{"$cls\::$name"} = $meth; } sub add_method_to_obj { my($obj, $name, $meth) = @_; my $class = ref $obj; (my $objcls = "$obj") =~ s/[^A-Z0-9]//ig; { no strict 'refs'; *{"$objcls\::ISA"} = [ @{"$class\::ISA"}, $class ]; } $_[0] = bless { %$obj }, $objcls; add_method_to_class($objcls, $name, $meth); } can_ok foo => 'hey'; can_ok foo => 'base'; eval { foo->new->yay } or pass "foo can't yay"; add_method_to_class('foo', yay => sub { "yay!" }); can_ok foo => 'yay'; my $o = foo->new; eval { $o->woo } or pass "\$o can't woo"; add_method_to_obj($o, woo => sub { "woo!" }); can_ok $o => 'woo'; eval { foo->new->woo } or pass "foo can't woo"; can_ok $o => 'base'; can_ok $o => 'hey';
    But if you're looking for a long-term robust solution then follow the sagacious davorg's advice.
    HTH

    _________
    broquaint

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://560891]
Approved by gellyfish
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others exploiting the Monastery: (6)
As of 2024-04-18 14:37 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found