2010-08-04 17 views
0

Nous essayons de créer une API pour prendre automatiquement en charge commit() et rollback(), afin que nous n'ayons plus à nous en préoccuper. En recherchant, nous avons trouvé que l'utilisation de eval {} est la voie à suivre. Pour savoir quoi faire, j'ai pensé à donner à l'API un tableau de fonctions, qu'il peut exécuter avec un foreach sans que l'API n'ait à interpréter quoi que ce soit. Toutefois, cette fonction peut être dans un package différent.A propos de l'utilisation d'un tableau de fonctions en Perl

Permettez-moi de préciser un exemple:

sub handler { 
    use OSA::SQL; 
    use OSA::ourAPI; 
    my @functions =(); 
    push(@functions, OSA::SQL->add_page($date, $stuff, $foo, $bar)); 
    my $API = OSA::ourAPI->connect(); 
    $API->exec_multi(@functions); 
} 

La question est la suivante: Est-il possible d'exécuter les fonctions @functions à l'intérieur de OSA::ourAPI, même si ourAPI n'a pas use OSA::SQL. Sinon, serait-ce possible si j'utilise une référence de tableau au lieu d'un tableau, étant donné que le pointeur pointe vers la fonction connue à l'intérieur de la mémoire?

Note: C'est l'idée de base sur laquelle nous voulons baser la version finale plus complexe.

+0

Je ne comprends pas ce que vous entendez par "exécuter les fonctions données dans OSA :: notreAPI". – cjm

+0

J'ai édité ma question pour clarifier. Les fonctions à l'intérieur de @functions sont celles dont je parle. – Mike

+0

'eval' est rarement le chemin à parcourir ... et mettre une instruction' use' dans une méthode ne retardera pas son exécution à l'exécution de la méthode. Il est exécuté immédiatement lorsque le fichier est analysé. – Ether

Répondre

4

  • Vous n'êtes pas ajoutez un pointeur de fonction à votre tableau. Vous ajoutez la valeur de retour de l'appel du sous-programme add_page(). Vous avez 3 solutions à ceci:

    A. Vous devrez stocker (dans @functions) un tableau de arrayrefs de la forme [\&OSA::SQL::add_page, @argument_values], signifiant que vous passez dans une référence réelle à un sous-programme (appelé statiquement); puis exec_multi fera quelque chose comme (la syntaxe ne peut pas être 100% correct car il est 4 heures ici)

     
    sub exec_multi { 
        my ($class, $funcs)= @_; 
        foreach my $f (@$funcs) { 
         my ($func, @args) = @$f; 
         my $res = &$func(@args); 
         print "RES:$res\n"; 
        } 
    } 
    

    Juste pour re-itérer, ce appellera sous-marins individuels en version statique (OSA::SQL::add_page), par exemple SANS passer le nom du paquet en tant que premier paramètre en tant qu'appel de classe OSA::SQL->add_page. Si vous voulez ce dernier, voir la solution suivante.


    B. Si vous voulez appeler vos sous-marins dans le contexte de classe (comme dans votre exemple, autrement dit avec le nom de classe comme premier paramètre), vous pouvez utiliser la suggestion de ysth dans le commentaire.

    Vous devrez stocker (dans @functions) un tableau de arrayrefs de la forme [sub { OSA::SQL->add_page(@argument_values) }], ce qui signifie que vous passez dans une référence à un sous-programme qui appellera à son tour ce que vous avez besoin; puis exec_multi fera quelque chose comme (la syntaxe ne peut pas être 100% correct car il est 4 heures ici)

     
    sub exec_multi { 
        my ($class, $funcs)= @_; 
        foreach my $f (@$funcs) { 
         my ($func) = @$f; 
         my $res = &$func(); 
         print "RES:$res\n"; 
        } 
    } 
    

    C.Vous devrez stocker (dans @functions) un tableau de arrayrefs de la forme [ "OSA::SQL", "add_page", @argument_values], ce qui signifie que vous transmettez un nom de package et de fonction; puis exec_multi fera quelque chose comme (la syntaxe ne peut pas être 100% correct car il est 4 heures ici)

     
    my ($package, $sub, @args) = @{ $functions[$i] }; 
    no strict 'refs'; 
    $package->$sub(@args); 
    use strict 'refs'; 
    

  • Si je comprends bien votre question, vous n'avez pas besoin vous vous demandez si notre API utilise OSA :: SQL, puisque votre code principal l'importe déjà.

    Cependant, puisque - dans # 1B - vous passerez une liste de paquets à exec_multi comme premiers éléments de chaque arrayref, vous pouvez faire "require $package; $package->import();" dans exec_multi. Mais encore une fois, il est complètement inutile si votre appel de gestionnaire déjà requis et chargé chacun de ces paquets. Et pour le faire correctement, vous devez également transmettre une liste de paramètres à import(). MAIS WHYYYYYY? :)

+2

'use $ package;' n'est pas légal. vous pouvez traduire un nom de module en un chemin relatif d'un fichier .pm, puis utiliser 'require'. Mieux vaut que les fonctions @ stockent simplement coderefs, donc: 'push @functions, sub {OSA :: SQL-> add_page ($ date, $ stuff, $ foo, $ bar)};' – ysth

+0

@ysth - LOL .. oui, je viens juste de réaliser les deux après avoir posté; mais ma solution à la seconde était légèrement différente. – DVK