2012-06-03 1 views

Respuesta

9

No realmente.

TL; DR:

  • Puede encontrar los nombres de subrutinas declarados o colocados en el espacio de nombres de clase del objeto de forma explícita.

  • Usted no puede distinguir cuál de estas subrutinas son métodos del objeto sobre el objeto y que son de clase o no a objetos submarinos (este es el problema más grave/limintation entre los enumerados).

  • NO puede encontrar los métodos heredados por un objeto en la subclase de la superclase usando este método, a menos que ya hayan sido invocados en su objeto.

    Esto se puede codificar alrededor, inspeccionando @ISA de la clase a build up inheritance trees, or using on of proper CPAN modules.

  • NO puede encontrar los métodos que se agregan dinámicamente a la clase (AUTOLOAD, la inyección manual de métodos en el código en alguna parte).

En detalle

  1. Puede encontrar todas las subrutinas de esa clase (combinando el hecho de que el espacio de nombres de clases es un hash de modo que todos los identificadores en que son claves en ese resumen ; y la llamada UNIVERSAL::can para separar subrutinas).

    Por lo tanto, si está GARANTIZADO (mediante un contrato no técnico) que el 100% de las subrutinas en la clase son métodos de objetos Y que su clase NO es una subclase, puede encontrar su lista.

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

    ... impresiones:

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

    Tenga en cuenta que la lista por primera vez (por MySubClass) impreso new y z3 pero NO x1y2 o - porque new fue ejecutado y fue declarado en z3 la clase; pero x1 y y2 tampoco fueron - fueron teóricamente heredados. PERO, una vez que ejecutamos un método x1 heredado, la segunda lista lo incluía, mientras que todavía faltaba el y2 heredado.


  2. pero no se puede, por desgracia, distinguir una subrutina que es un método de objeto (por ejemplo, trata el primer argumento se pone como un objeto), un método de clase (por ejemplo, trata el primer argumento se pone como una clase nombre) o un sub no OO (trata el primer argumento como argumento regular).

    Para distinguir entre los 3, la ÚNICA forma es analizar semánticamente el código. De lo contrario, no se puede decir la diferencia entre:

    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 
    

    NOTA: Como cuestión de hecho, algunas personas realmente escriben los métodos de su clase - los que pueden trabajar de esta manera - para trabajar de forma explícita en todos los 3 (o primera 2) casos, no importa cómo se llame el método.

+0

* "NO puede encontrar los métodos heredados por un objeto en la subclase de la superclase, a menos que ya hayan sido invocados en su objeto" *. Si le leo correctamente, ¿está diciendo que '$ obj-> inherited_method' debe ejecutarse antes de que pueda detectar' inherited_method'? No creo que sea cierto o [estas pruebas perl5i] (https://metacpan.org/source/MSCHWERN/perl5i-v2.9.1/t/Meta/methods.t) no funcionarían. ¿Tienes código para respaldar eso? – Schwern

+0

@Schwern - vea la segunda oración en esa viñeta: "Esto puede codificarse, ya sea inspeccionando ISA de la clase para construir árboles de herencia, o usando los módulos de CPAN apropiados". La parte "Can NOT" se refería a la técnica resumida anteriormente de lectura directa del hash del espacio de nombres. El código de copia de seguridad de esta declaración (menos grandiouse de lo que lees) es mi código en la respuesta. – DVK

+0

Oh. Acabo de tomar caminando '@ ISA' como algo dado. – Schwern

0

La respuesta de DVK es precisa, pero un poco larga. La respuesta breve es sí, puede, pero no sabrá qué se pretendía como método de objeto público y qué no. Los métodos privados y las funciones importadas de otros módulos pueden aparecer.

La forma más simple de obtener la lista de métodos invocables, concretos (es decir, no AUTOLOAD) es usar el método perl5i meta objectmethods().

use perl5i::2; 

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

Eso al menos elimina una gran cantidad de código.

+0

¿Cómo distinguen 'methods' entre los métodos del objeto y los subs no objeto de la clase (ver mis 3 ejemplos en la parte n. ° 2)? POD no parecía tener ninguna aclaración sobre eso. – DVK

+0

Además, ¿se trata correctamente con cosas AUTOLOADed? – DVK

+0

@DVK Simple: no es así. Como correctamente señaló, no puede. Simplemente enumera los métodos disponibles, concretos e invocables que hacen todo el recorrido de herencia y el examen de la tabla de símbolos para que no tenga que hacerlo. Corregiré algunos pronombres en mi respuesta para aclarar esto. * Podría * aprovechar la distinción func/método de perl5i, pero actualmente no lo hace. – Schwern

Cuestiones relacionadas