We are trying to build an API to support commit() and rollback() automatically, so that we don’t have to bother with it anymore. By researching, we have found that using eval {} is the way to go.
For eval {} to know what to do, I have thought of giving the API an array of functions, which it can execute with a foreach without the API having to intepret anything. However, this function might be in a different package.
Let me clarify with an example:
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);
}
The question is: Is it possible to execute the functions in @functions inside of OSA::ourAPI, even if ourAPI has no use OSA::SQL. If not, would it be possible if I use an array reference instead of an array, given that the pointer would point to the known function inside of the memory?
Note: This is the basic idea that we want to base the more complex final version on.
You are NOT adding a function pointer to your array. You are adding teh return value of calling the add_page() subroutine. You have 3 solutions to this:
A. You will need to store (in
@functions) an array of arrayrefs of the form[\&OSA::SQL::add_page, @argument_values], meaning you pass in an actual reference to a subroutine (called statically); and then exec_multi will do something like (syntax may not be 100% correct as it’s 4am here)sub exec_multi { my ($class, $funcs)= @_; foreach my $f (@$funcs) { my ($func, @args) = @$f; my $res = &$func(@args); print "RES:$res\n"; } }Just to re-iterate, this will call individual subs in static version (
OSA::SQL::add_page), e.g. WITHOUT passing the package name as the first parameter as a class callOSA::SQL->add_pagewould. If you want the latter, see the next solution.B. If you want to call your subs in class context (like in your example, in other words with the class name as a first parameter), you can use ysth’s suggestion in the comment.
You will need to store (in
@functions) an array of arrayrefs of the form[sub { OSA::SQL->add_page(@argument_values) }], meaning you pass in a reference to a subroutine which will in turn call what you need; and then exec_multi will do something like (syntax may not be 100% correct as it’s 4am here)sub exec_multi { my ($class, $funcs)= @_; foreach my $f (@$funcs) { my ($func) = @$f; my $res = &$func(); print "RES:$res\n"; } }C. You will need to store (in
@functions) an array of arrayrefs of the form[ "OSA::SQL", "add_page", @argument_values], meaning you pass in a package and function name; and then exec_multi will do something like (syntax may not be 100% correct as it’s 4am here)my ($package, $sub, @args) = @{ $functions[$i] }; no strict 'refs'; $package->$sub(@args); use strict 'refs';If I understood your question correctly, then you don’t need to worry about whether ourAPI uses OSA::SQL, since your main code imports it already.
However, since – in #1B – you will be passing a list of packages to exec_multi as first elements of each arrayref, you can do “
require $package; $package->import();” in exec_multi. But again, it’s completely un-necessary if your handler call already required and loaded each of those packages. And to do it right you need to pass in a list of parameters toimport()as well. BUT WHYYYYYY? 🙂