Pergunta

Estamos tentando criar uma API para apoiar o Commit () e Rollback () automaticamente, para que não precisemos mais nos incomodar com isso. Pesquisando, descobrimos que usar eval {} é o caminho a percorrer.

Por eval {} Para saber o que fazer, pensei em dar à API uma variedade de funções, que ela pode executar com um foreach sem a API ter que interpretar nada. No entanto, essa função pode estar em um pacote diferente.

Deixe -me esclarecer com um exemplo:

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

A questão é: é possível executar as funções em @functions dentro de OSA::ourAPI, mesmo que nossapi não tenha use OSA::SQL. Caso contrário, seria possível se eu usar uma referência de matriz em vez de uma matriz, já que o ponteiro apontaria para a função conhecida dentro da memória?

Nota: Esta é a ideia básica em que queremos basear a versão final mais complexa.

Foi útil?

Solução


  • Você não está adicionando um ponteiro de função à sua matriz. Você está adicionando o valor de retorno de chamar a sub -rotina add_page (). Você tem 3 soluções para isso:

    A. Você precisará armazenar (em @functions) uma variedade de ArrayRefs da forma [\&OSA::SQL::add_page, @argument_values], o que significa que você passa em uma referência real a uma sub -rotina (chamada estaticamente); E então Exec_multi fará algo como (a sintaxe pode não estar 100% correta, pois são 4 da manhã aqui)

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

    Apenas para reiterar, isso chamará de subs individual na versão estática (OSA::SQL::add_page), por exemplo, sem passar o nome do pacote como o primeiro parâmetro como uma chamada de classe OSA::SQL->add_page gostaria. Se você quiser o último, consulte a próxima solução.


    B. Se você deseja chamar seus subs em contexto de classe (como no seu exemplo, em outras palavras com o nome da classe como primeiro parâmetro), você pode usar a sugestão do YSTH no comentário.

    Você precisará armazenar (em @functions) uma variedade de ArrayRefs da forma [sub { OSA::SQL->add_page(@argument_values) }], o que significa que você passa em uma referência a uma sub -rotina que, por sua vez, chamará o que você precisa; E então Exec_multi fará algo como (a sintaxe pode não estar 100% correta, pois são 4 da manhã aqui)

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

    C. Você precisará armazenar (em @functions) uma variedade de ArrayRefs da forma [ "OSA::SQL", "add_page", @argument_values], o que significa que você passa em um pacote e nome da função; E então Exec_multi fará algo como (a sintaxe pode não estar 100% correta, pois são 4 da manhã aqui)

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

  • Se eu entendi sua pergunta corretamente, você não precisa se preocupar se o OurApi usa OSA :: SQL, já que o seu código principal já a importa.

    No entanto, desde - no #1B - você passará uma lista de pacotes para exec_multi como os primeiros elementos de cada arrayref, você pode fazer "require $package; $package->import();"Em Exec_multi. Mas, novamente, é completamente desconthery se o seu manipulador já é necessário e carregar cada um desses pacotes. E para fazê-lo corretamente, você precisa passar em uma lista de parâmetros para import() também. Mas por queyyyyy? :)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top