Perl llamadas a métodos son subprogramas simplemente regulares, que obtienen las invocaciones como el primer valor.
use strict;
use warnings;
use 5.10.1;
{
package MyPackage;
sub new{ bless {}, shift } # overly simplistic constructor (DO NOT REUSE)
sub echo{ say @_ }
}
my $package_name = 'MyPackage';
$package_name->echo;
my $object = $package_name->new();
$object->echo; # effectively the same as MyPackage::echo($object)
MyPackage
MyPackage=HASH(0x1e2a070)
Si desea llamar a una subrutina sin invocaciones, tendrá que llamar de otra manera.
{
no strict 'refs';
${$package_name.'::'}{echo}->('Hello World');
&{$package_name.'::echo'}('Hello World');
}
# only works for packages without :: in the name
$::{$package_name.'::'}{echo}->('Hello World');
$package_name->can('echo')->('Hello World');
El método can
devuelve una referencia a la subrutina que se llamaría si hubiera sido llamado a las invocaciones. El coderef puede usarse por separado.
my $code_ref = $package_name->can('echo');
$code_ref->('Hello World');
hay algunas advertencias para el uso de can
:
can
puede ser anulado por el paquete, o cualquier clase de la que hereda.
- El paquete que define un método puede ser diferente al invocante.
Este puede ser el comportamiento que estás buscando.
Otro enfoque es utilizar algo llamado symbolic reference.
{
no strict 'refs';
&{ $package_name.'::echo' }('Hello World');
}
No se recomienda el uso de referencias simbólicas. Parte del problema es que es posible utilizar accidentalmente una referencia simbólica en la que no tenía la intención de usarla. Es por eso que no puede tener use strict 'refs';
vigente.
Esta puede ser la forma más sencilla de hacer lo que quiera hacer.
Si no desea utilizar una referencia simbólica, puede utilizar el Stash.
$MyPackage::{echo}->('Hello World');
$::{'MyPackage::'}{echo}->('Hello World');
$main::{'MyPackage::'}{echo}->('Hello World');
$main::{'main::'}{'MyPackage::'}{echo}->('Hello World');
$main::{'main::'}{'main::'}{'main::'}{'MyPackage::'}{echo}->('Hello World');
El único problema con esto es que usted tiene que dividir en $package_name
::
*Some::Long::Package::Name::echo = \&MyPackage::echo;
$::{'Some::'}{'Long::'}{'Package::'}{'Name::'}{echo}('Hello World');
sub get_package_stash{
my $package = shift.'::';
my @package = split /(?<=::)/, $package;
my $stash = \%:: ;
$stash = $stash->{$_} for @package;
return $stash;
}
get_package_stash('Some::Long::Package::Name')->{echo}('Hello World');
Esto no es tan grande de un problema. Después de un rápido vistazo al CPAN, encontrará Package::Stash.
use Package::Stash;
my $stash = Package::Stash->new($package_name);
my $coderef = $stash->get_symbol('&echo');
$coderef->('Hello World');
(La versión Pure Perl de Package::Stash utiliza referencias simbólicas, no el alijo)
Es incluso posible hacer un alias de la subrutina/método, como si había sido importado de un módulo que estaba usando Exporter:
*echo = \&{$package_name.'::echo'};
echo('Hello World');
lo haría r ecommend limitar el alcance del alias embargo:
{
local *echo = \&{$package_name.'::echo'};
echo('Hello World');
}
Ésta es una excepción, donde se puede utilizar una referencia simbólica con strict 'refs'
habilitado.
Si no quiere pasar a un invocante, entonces lo que quiere es no llamar a un * método *. – hobbs
@hobbs: Gracias. Actualicé la pregunta para usar una terminología más correcta. – Sam