Is there any way to find out methods of an instance of an unknown class in Perl

I have a program in Perl that uses a package that I received from another source. One of the functions of the method returns an object of an unknown class. Is there a way to get all possible methods of an object without looking at its implementation of the class?

+5
source share
2 answers

Not really.

TL; DR:

  • You can find the names of routines explicitly declared or placed in the namespace of the object classes.

  • You cannot distinguish which of these routines are object methods on your object and which are class or non-object objects (this is the most serious problem / limitation among those listed).

  • You cannot find methods inherited by an object in a subclass of a superclass using this method if they have already been called on your object.

    This can be encoded by checking the @ISA class for creating inheritance trees or using the correct CPAN modules .

  • You cannot find methods that are dynamically added to the class (AUTOLOAD, manual method injection in code somewhere).

More details

  • You can find all the subroutines of this class (combining the fact that the class namespace is a hash, so all identifiers in it are keys in this hash, and the UNIVERSAL::can call is for individual subroutines).

    Therefore, if you are GUARANTEED (under a non-technical contract) that 100% of the routines in the class are object methods, and that your class is NOT a subclass, you can find a list of them.

     package MyClass; use vars qw($z5); my $x = 11; our $y = 12; $z5 = 14; %z2 = (1=>2); # my, our, globals, hash sub new { return bless({}, $_[0]) }; # Constructor sub x1 { my $self = shift; print $_[0]; }; sub y2 { my $self = shift; print $_[0]; }; ############################################################################## package MySubClass; use vars qw(@ISA); @ISA = ("MyClass"); sub z3 { return "" }; ############################################################################## package main; use strict; use warnings; my $obj = MyClass->new(); list_object_methods($obj); my $obj2 = MySubClass->new(); list_object_methods($obj2); $obj2->x1(); list_object_methods($obj2); # Add "x1" to the list! sub list_object_methods { my $obj = shift; my $class_name = ref($obj); no strict; my @identifiers = keys %{"${class_name}::"}; use strict; my @subroutines = grep { UNIVERSAL::can($obj, $_) } @identifiers; print "Class: ${class_name}\n"; print "Subroutines: \n=========\n" . join("\n", sort @subroutines) . "\n=========\n"; } 

    ... prints:

     Class: MyClass Subroutines: ========= new x1 y2 ========= Class: MySubClass Subroutines: ========= new z3 ========= Class: MySubClass Subroutines: ========= new x1 z3 ========= 

    Note that the first time (for MySubClass) new and z3 printed, but NOT x1 or y2 - because new was executed, and z3 was declared in the class; but x1 and y2 were not - they were just theoretically inherited. BUT, as soon as we executed the inherited method x1 , then turned it on a second time until it received the inherited y2 .


  • But you cannot, unfortunately, distinguish between a subroutine that is an object method (for example, treats the first argument that it receives as an object), a class method (for example, treats the first argument that it receives as a class name) or non-OO sub (treats the first argument as a regular argument).

    To distinguish 3, the only way is to actually semantically analyze the code. Otherwise, you cannot tell the difference between:

     sub s_print_obj { my ($self, $arg1) = @_; $s->{arg1} = $arg1; print "$arg1\n"; } # $obj->s_print_obj("XYZ") prints "XYZ" and stores the data in the object sub s_print_class { my ($class, $arg1) = @_; print "Class: $class\n"; print "$arg1\n"; } # $obj->s_print_class("XYZ") prints "Class: MyClass\nXYZ\n" sub s_print_static { my ($self, $arg1) = @_; print "$arg1\n"; } # $obj->s_print_static("XYZ") prints stringified representation of $obj 

    NOTE. In fact, some people actually write their class methods - those that CAN work this way - explicitly work in all cases 3 (or the first 2), regardless of how the method is called.

+9
source

The DVK answer is accurate, but a bit long. The short answer is yes, you can, but you will not know what was intended as a public object method and what was not. Private methods and functions imported from other modules may be displayed.

The easiest way to get a list of callable, specific (i.e. non-AUTOLOAD) methods is to use the meta object perl5i methods () .

 use perl5i::2; my $object = Something::Something->new; my @methods = $object->mo->methods; 

This at least eliminates a lot of code.

0
source

All Articles