有没有办法知道 Perl 中未知类的实例的方法 [英] Is there a way to know the methods of an instance of an unknown class in Perl

查看:55
本文介绍了有没有办法知道 Perl 中未知类的实例的方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 Perl 程序,它使用我从另一个来源获得的包.方法的一个函数返回一个未知类的对象,有没有办法不看它的类实现就得到一个对象的所有可能的方法?

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

推荐答案

并非如此.

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.

这可以编码,通过检查类的 @ISA建立继承树,或使用适当的 CPAN 模块.

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

您无法找到动态添加到类中的方法(AUTOLOAD,代码中的手动方法注入某处).

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

详细

  1. 您可以找到该类中的所有子例程(通过结合类命名空间是一个散列,因此其中的所有标识符都是该散列中的键这一事实;以及 UNIVERSAL::can 调用单独的子程序).

  1. 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).

因此,如果您保证(通过非技术合同)类中的子程序 100% 是对象方法,并且您的类不是子类,您可以找到它们的列表.

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";
}

...打印:

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

请注意第一次列表(对于 MySubClass)打印了 newz3 但不是 x1y2 - 因为 new 被执行并且 z3 在类中被声明;但是 x1y2 都不是——它们只是理论上继承的.但是,一旦我们执行了继承的 x1 方法,那么第二次列表包含它,同时仍然缺少继承的 y2.

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.

但是,不幸的是,您不能区分作为对象方法的子例程(例如,将其获取的第一个参数视为对象)和类方法(例如,将其获取的第一个参数视为类名)或非 OO 子(将第一个参数视为常规参数).

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).

要区分这 3 种,唯一的方法是实际对代码进行语义分析.否则,您无法分辨两者之间的区别:

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

注意:事实上,有些人实际上编写了他们的类的方法 - 那些可以以这种方式工作的方法 - 显式地在所有 3(或前 2 个)情况下工作,无论该方法如何调用.

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.

这篇关于有没有办法知道 Perl 中未知类的实例的方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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