Comment un objet accède-t-il à la table des symboles pour le package actuel?

StackOverflow https://stackoverflow.com/questions/1822312

  •  10-07-2019
  •  | 
  •  

Question

Comment accéder à la table des symboles du package actuel dans lequel un objet a été instancié? Par exemple, j'ai quelque chose comme ça:

my $object = MyModule->new;
# this looks in the current package, to see if there's a function named run_me
# I'd like to know how to do this without passing a sub reference
$object->do_your_job;

Si, dans la mise en œuvre de do_your_job , j'utilise __ PACKAGE __ , la recherche s'effectuera dans le package MyModule . Comment puis-je le faire apparaître dans le bon paquet?

EDIT: Je vais essayer de rendre cela plus clair. Supposons que j'ai le code suivant:

package MyMod;

sub new {
    return bless {},

Comment accéder à la table des symboles du package actuel dans lequel un objet a été instancié? Par exemple, j'ai quelque chose comme ça:

my $object = MyModule->new;
# this looks in the current package, to see if there's a function named run_me
# I'd like to know how to do this without passing a sub reference
$object->do_your_job;

Si, dans la mise en œuvre de do_your_job , j'utilise __ PACKAGE __ , la recherche s'effectuera dans le package MyModule . Comment puis-je le faire apparaître dans le bon paquet?

EDIT: Je vais essayer de rendre cela plus clair. Supposons que j'ai le code suivant:

<*>

Désormais, $ x devrait en quelque sorte remarquer que main est le paquet actuel et effectuer une recherche dans la table des symboles. J'ai essayé d'utiliser la bénédiction de Scalar :: Util , mais cela m'a tout de même donné MyModule au lieu de main . Espérons que cela soit un peu plus clair maintenant.

[0] } sub do_your_job { my $self = shift; # of course find_package_of is fictional here # just for this example's sake, $pkg should be main my $pkg = find_package_of($self); if(defined &{ $pkg . '::run_me' }) { # the function exists, call it. } } package main; sub run_me { print "x should run me.\n"; } my $x = MyMod->new; # this should find the run_me sub in the current package and invoke it. $x->do_your_job;

Désormais, $ x devrait en quelque sorte remarquer que main est le paquet actuel et effectuer une recherche dans la table des symboles. J'ai essayé d'utiliser la bénédiction de Scalar :: Util , mais cela m'a tout de même donné MyModule au lieu de main . Espérons que cela soit un peu plus clair maintenant.

Était-ce utile?

La solution

Vous voulez simplement appelant

appelant vous indique le paquet à partir duquel il a été appelé. (Ici j'ai ajouté du perl standard.)

use Symbol qw<qualify_to_ref>;
#...
my $pkg = caller;

my $symb   = qualify_to_ref( 'run_me', $pkg );
my $run_me = *{$symb}{CODE};
$run_me->() if defined $run_me;

L'examiner et voir s'il est défini, puis l'appel, il le dupliquerait, car le langage standard n'est pas perl, il ne faut pas éliminer les sous-expressions communes. Vous pourriez donc tout aussi bien 1) le récupérer et 2) vérifier le caractère défini de l'emplacement, et 3) l'exécuter s'il est défini.

Maintenant, si vous créez un objet dans un package et l'utilisez dans un autre, vous n'aurez pas besoin de beaucoup d'aide. Vous devrez probablement ajouter un champ supplémentaire tel que 'owning_package' dans le constructeur.

package MyMod;

#...
sub new { 
    #...
    $self->{owning_package} = caller || 'main';
    #...
}

Maintenant, $ x - > {owning_package} contiendra 'main' .

Autres conseils

Voir appelant perldoc -f :

#!/usr/bin/perl

package A;
use strict; use warnings;

sub do_your_job {
    my ($self) = @_;
    my ($pkg) = caller;
    if ( my $sub = $pkg->can('run_me') ) {
        $sub->();
    }
}

package B;
use strict; use warnings;

sub test {
    A->do_your_job;
}

sub run_me {
    print "No, you can't!\n";
}

package main;

use strict; use warnings;

B->test;

Sortie:

C:\Temp> h
No, you can't!
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top