Вопрос по perl – Как мне перебрать все методы класса в Perl?

9

Как вы перебираете все методы класса в Perl? Есть ли в Интернете хорошие ссылки на интроспекцию или рефлексию Perl?

По первому вопросу смотрите:stackoverflow.com/questions/910430/… molf

Ваш Ответ

6   ответов
5

о вы не используете Moose). Например, чтобы перечислить методы, определенные вIO::File пакет:

use IO::File;
no strict 'refs';
print join ', ', grep { defined &{"IO::File::$_"} } keys %{IO::File::};

Хеш%{IO::File::} таблица символовIO::File packageиgrep отфильтровывает записи без подпрограмм (например, переменные пакета).

Чтобы расширить это, чтобы включить унаследованные методы, вы должны рекурсивно искать таблицы символов родительских классов (@IO::File::ISA).

Вот полный пример:

sub list_methods_for_class {
    my $class = shift;
    eval "require $class";
    no strict 'refs';
    my @methods = grep { defined &{$class . "::$_"} } keys %{$class . "::"};
    push @methods, list_methods_for_class($_) foreach @{$class . "::ISA"};
    return @methods;
}

Для получения дополнительной информации о пакетах и таблицах символов см.perlmod справочная страница.

Не каждый метод должен быть определен в таблице символов, и вам не хватает UNIVERSAL.
Мне было интересно, если какое-либо из решений для этого вопроса, в частности, здесь, генерирует новый экземпляр объекта каждый раз, когда вызывается код, и если он перерабатывается или каждый экземпляр остается в памяти до завершения программы. Поскольку использование рефлексии / самоанализа в некоторых других языках, таких как .NET и Java, необходимо соблюдать осторожность, когда создавать экземпляр ссылки на объект класса, иначе можно получить новые экземпляры за вызов.
13

которую Тодд Гарднер дал использовать Moose, является хорошей, но пример кода, который он выбрал, не очень полезен.

Если вы проверяете класс, не использующий Moose, вы делаете что-то вроде этого:

use Some::Class;
use Class::MOP;

my $meta = Class::MOP::Class->initialize('Some::Class');

for my $meth ( $meta->get_all_methods ) {
    print $meth->fully_qualified_name, "\n";
}

УвидетьКласс :: MOP :: Класс документов  для более подробной информации о том, как сделать самоанализ.

Вы также заметите, что я использовал Class :: MOP вместо Moose. Class :: MOP (MOP = Meta-Object Protocol) является основой, на которой строится Moose. Если вы работаете с классами, не относящимися к Moose, использование Moose для самоанализа ничего не даст вам.

Если бы вы хотели, вы могли быuse Moose () а такжеMoose::Meta::Class->initialize вместо CMOP.

@ Brian D Foy: использование AUTOLOAD плохо, мммкей?
+1: это здорово, я не знал, что вы могли бы использовать Class :: MOP вот так.
Я объясняю ограничения этого в своем ответе. Даже с пустым классом он не может выбрать методы из UNIVERSAL и не может выбрать любой из AUTOLOAD.
0

Жаль, что это настолько необычно, что большинство программистов на Perl никогда не испытывают этого.

package Foo;
use strict;
sub foo1 {};
sub foo2 {};
our $foo3 = sub{};
my $foo4 = "hello, world!";

package Bar;
use strict;

# woo, we're javascript!
(sub {
    *Bar::foo1 = sub { print "hi!"; };
    *Bar::foo2 = sub { print "hello!"; };
    $Bar::foo1 = 200;
})->();

package main;
use strict;
use Data::Dumper;      
$Data::Dumper::Deparse = 1;

print Dumper \%Data::Dumper::;
print Dumper \%Foo::;
print Dumper \%Bar::;
3

имеете ли вы в виду какой-либо класс или реализуете свой собственный. Для последнего я используюлось, который предлагает очень чистый синтаксис для этих функций. Из кулинарной книги:

my %attributes = %{ $self->meta->get_attribute_map };
for my $name ( sort keys %attributes ) {
   my $attribute = $attributes{$name};

   if (   $attribute->does('MyApp::Meta::Attribute::Trait::Labeled')
   # ... keeps on
Обратите внимание, что Moose не найдет никаких атрибутов, если только класс, который вы анализируете, не был определен с помощью Moose. Однако метод самоанализа, как и большинство других битов, будет работать просто отлично.
10

используя уже предоставленные ответы. Тем не менее, Perl является динамическим языком, что означает, что другие методы могут быть определены позже. На самом деле нет способа получить список всех методов, с которыми будет работать какой-либо конкретный класс. Для более подробной информации о подобных вещах у меня есть несколько главОсвоение Perl.

Люди дают вам (и голосуют против) ответы, не сообщая вам об ограничениях.

Адам упоминает егоКласс :: Инспектор, но это на самом деле не работает, потому что он пытается сделать что-то, что динамический язык не делает (и это статично :) Например, здесь фрагмент кода, в котором Class :: Inspector не возвращает никаких методов, но я можно еще назватьVERSION метод (а такжеisa а такжеcan):

    BEGIN {

package Foo;

our $VERSION = '1.23'
}

use Class::Inspector;

my $methods = Class::Inspector->methods( 'Foo' );

print "Methods are [@$methods]\n"; # reports nothing

print Foo->VERSION, "\n";

Вот еще один случай, когда я могу вызвать любой метод, который мне нравится, но Class :: Inspector возвращает толькоAUTOLOAD (и до сих пор отсутствуетVERSION, isa, а такжеcan):

BEGIN {

package Foo;

our $VERSION = '1.23';

my $object = bless {}, __PACKAGE__;

sub AUTOLOAD { $object }

}

use Class::Inspector;

my $methods = Class::Inspector->methods( 'Foo' );

print "Methods are [@$methods]\n"; # reports only "AUTOLOAD"

print Foo->dog->cat->bird, "\n";

Любопытно, что все, кажется, игнорируют UNIVERSAL, возможно, потому, что они явно не обращаются с ним, поскольку это происходит только в @ISA. Я могу добавитьdebug метода для каждого класса, и Class :: Inspector по-прежнему пропускает его, даже если это определенный метод:

BEGIN {

sub UNIVERSAL::debug { "Hello debugger!\n" }    
package Foo;
}

use Class::Inspector;

my $methods = Class::Inspector->methods( 'Foo' );

print "Methods are [@$methods]\n"; # still reports nothing

print Foo->debug, "\n";

Класс :: MOP имеет те же ограничения.

Не каждый модуль будет использовать AUTOLOAD, но он также не является скрытой или редкой функцией. Если вы не возражаете против того, что вы пропустите некоторые методы, то Class :: Inspector или Class :: MOP могут подойти. Он просто не даст вам список всех методов, которые вы можете вызывать для класса или объекта в каждом случае.

Если у вас есть класс или объект, и вы хотите знать, можете ли вы вызвать конкретный метод, используйте can (). Оберните его в блок eval, чтобы функция can () могла вызывать вещи, которые не являются даже объектами, чтобы в тех случаях возвращать ложь вместо смерти, в следующих случаях:

if( eval { $object->can( 'method_name' ) } )
    {
    $object->( @args );
    }
3

Your :: Class & apos;).

Достаточно.

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