Вопрос по perl – Есть ли способ узнать методы экземпляра неизвестного класса в Perl

5

У меня есть программа на Perl, которая использует пакет, полученный из другого источника. Одна из функций метода возвращает объект неизвестного класса. Есть ли способ для меня получить все возможные методы объекта, не глядя на реализацию его класса?

Ваш Ответ

2   ответа
0

да, вы можете, но вы не будете знать, что было задумано как метод публичного объекта, а что нет. Частные методы и функции, импортированные из других модулей, могут отображаться.

Простейший способ получить список вызываемых, конкретных (т.е. не-AUTOLOAD) методов - использоватьметаобъект perl5i& APOS; sметоды () метод.

use perl5i::2;

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

Это, по крайней мере, устраняет много кода.

Error: User Rate Limit Exceeded
Error: User Rate Limit ExceededmethodsError: User Rate Limit Exceeded
Error: User Rate Limit ExceededcouldError: User Rate Limit Exceeded
Error: User Rate Limit Exceeded"Method" has a very specific connotation/meaningError: User Rate Limit Exceededincluding Perl
Error: User Rate Limit ExceededI'd rather you put the energy into improving it. :)
9

TL;DR:

You can find the names of subroutines explicitly declared or placed into the object's class's namespace.

You can NOT distinguish which of these subroutines are object methods on your object, and which are class or non-object subs (this is the most serious problem/limintation among those listed).

You can NOT find the methods inherited by an object in the subclass from the superclass using this method, unless they were already called on your object.

This can be coded around, by either inspecting @ISA of the class to build up inheritance trees, or using on of proper CPAN modules.

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

In detail

You can find all of the subroutines in that class (by combining the fact that the class namespace is a hash so all identifiers in it are keys in that hash; and the UNIVERSAL::can call to separate subroutines).

Therefore, if you are GUARANTEED (by non-technical contract) that 100% of subroutines in the class are object methods, AND that your class is NOT a subclass, you can find their list.

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
=========

Please note that the first-time list (for MySubClass) printed new and z3 but NOT x1 or y2 - because new was executed and z3 was declared in the class; but x1 and y2 was neither - they were merely theoretically inherited. BUT, once we executed an inherited x1 method, then the second-time list included it, while still missing inherited y2.

But you can NOT, unfortunately, distinguish a subroutine that is an object method (e.g. treats the first argument it gets as an object), a class method (e.g. treats the first argument it gets as a class name) or a non-OO sub (treats first argument as regular argument).

To distinguish between the 3, the ONLY way is to actually semantically analyze the code. Otherwise, you can't 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: As a matter of fact, some people actually write their class's methods - those that CAN work this way - to explicitly work in ALL 3 (or first 2) cases, no matter how the method is called.

Error: User Rate Limit Exceeded@ISAError: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
"You can NOT find the methods inherited by an object in the subclass from the superclass, unless they were already called on your object"Error: User Rate Limit Exceeded$obj->inherited_methodError: User Rate Limit Exceededinherited_methodError: User Rate Limit Exceededthese perl5i testsError: User Rate Limit Exceeded

Похожие вопросы