2010-08-04 6 views
0

Мы пытаемся создать API для поддержки commit() и rollback() автоматически, так что нам больше не нужно его беспокоить. Исследуя, мы обнаружили, что использование eval {} - это путь.Об использовании массива функций в Perl

eval {} Чтобы узнать, что делать, я подумал о предоставлении API-массива функций, которые он может выполнить с помощью foreach без API, который должен что-либо сделать. Однако эта функция может быть в другом пакете.

Поясню на примере:

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

Возникает вопрос: можно ли выполнять функции в @functions внутри OSA::ourAPI, даже если ourAPI не имеет use OSA::SQL. Если нет, возможно ли, если я использую ссылку на массив вместо массива, учитывая, что указатель указывает на известную функцию внутри памяти?

Примечание: Это основная идея, на которой мы хотим основать более сложную окончательную версию.

+0

Я не понимаю, что вы подразумеваете под «выполнением заданных функций внутри OSA :: ourAPI». – cjm

+0

Я отредактировал мой вопрос, чтобы уточнить. Функции внутри @functions - это те, о которых я говорю. – Mike

+0

'eval' редко бывает ... и добавление оператора' use' внутри метода не задерживает его выполнение до того, как будет запущен метод. Он выполняется сразу же после анализа файла. – Ether

ответ

4

  • Вы НЕ добавить указатель на функцию в массив. Вы добавляете возвращаемое значение для вызова подпрограммы add_page(). У вас есть 3 решения это:

    A. Вам нужно будет хранить (в @functions) массив arrayrefs формы [\&OSA::SQL::add_page, @argument_values], то есть вы передаете в реальной ссылке на подпрограмму (так называемой статический); а затем exec_multi будет делать что-то вроде (синтаксис не может быть 100% правильно, как это 4 утра здесь)

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

    Просто повторно итерацию, это будет вызывать индивидуальные подлодки в статическом исполнении (OSA::SQL::add_page), например, БЕЗ передачи имени пакета в качестве первого параметра в качестве вызова класса OSA::SQL->add_page. Если вы хотите последний, см. Следующее решение.


    B. Если вы хотите назвать свои подводные лодки в контексте класса (как в вашем примере, другими словами, с именем класса в качестве первого параметра), вы можете использовать предложение ysth в комментарии.

    Вам необходимо будет хранить (в @functions) массив arrayrefs формы [sub { OSA::SQL->add_page(@argument_values) }], что означает, что вы передаете ссылку на подпрограмму, которая в свою очередь вызовет то, что вам нужно; а затем exec_multi будет делать что-то вроде (синтаксис не может быть 100% правильно, как это 4 утра здесь)

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

    C.Вам нужно будет хранить (в @functions) массив arrayrefs формы [ "OSA::SQL", "add_page", @argument_values], что означает, что вы передаете имя пакета и функции; а затем exec_multi будет делать что-то вроде (синтаксис не может быть 100% правильно, как это 4 утра здесь)

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

  • Если я правильно понял ваш вопрос, то вам не нужно беспокоиться о том, использует ли наш API OSA :: SQL, поскольку ваш основной код импортирует его уже.

    Однако, поскольку - в # 1B - вы передадите список пакетов exec_multi в качестве первых элементов каждого arrayref, вы можете сделать «require $package; $package->import();» в exec_multi. Но опять же, это совершенно не необходимо, если ваш обработчик уже требует и загружает каждый из этих пакетов. И для этого вам нужно перейти в список параметров и до import(). НО WHYYYYYY? :)

+2

'use $ package;' не является законным. вы можете перевести имя модуля в относительный путь к файлу .pm, а затем использовать 'require'. Лучше иметь @функции, просто хранить coderefs, так: 'push @functions, sub {OSA :: SQL-> add_page ($ date, $ stuff, $ foo, $ bar)};' – ysth

+0

@ysth - LOL .. Я просто понял, что сразу после публикации; хотя мое решение второго было несколько иным. – DVK