I am as lowly as they come in the art of Perl, however I decided I will rewrite my old bash accounts program into Perl and PHP.

I have the accounts program up and running in Perl and PHP but because I cannot get my head around passing variables to and from subroutines in Perl it is currently very clunky. How clunky?-well read on.

Here is my problem. I have many plans for my customers which involve deducing the cost of each plan based on the amount of megabytes used.

I have a file for each plan containing the maths and I pass the megabytes used by the customer by putting the number of Megabytes used into a file and getting the plan to read the file.

I then calculate the retail cost, wholesale cost, extracost, profit of each plan.

I then return the name of the plan, wholesale cost, retail cost, extracost and the profit margin to yet another file and get the main program to read the file and use the results to bill the clients. Which is about as clunky as you can get.

Here is an example of the math structure of these plans (I currently have around 50 different plans).

That tutorial is exactly the same as the book programing Perl and thats what prompted me to ask the question here in the first place

I was hoping to get a more direct path to the answer as I am struggling with Perl let alone trying to make a comparison to C as this sentance from the tutorial does.

because a lexical variable is lexically (also called statically) scoped to its enclosing block, eval, or do FILE, this doesn't mean that within a function it works like a C static. It normally works more like a C auto, but with implicit garbage collection.

That tutorial is exactly the same as the book programing Perl and thats what prompted me to ask the question here in the first place

I was hoping to get a more direct path to the answer as I am struggling with Perl let alone trying to make a comparison to C as this sentance from the tutorial does.

because a lexical variable is lexically (also called statically) scoped to its enclosing block, eval, or do FILE, this doesn't mean that within a function it works like a C static. It normally works more like a C auto, but with implicit garbage collection.

Well, I am not sure if you are simply asking how to pass arguments and return results or if you are asking how to use static variables with perl. Passing in arguments to subroutines and returning results is straight forward and simple. Using static variables is accomplished in perl 5.10 using the "state" function. You can also create static varaibles using "my" and enclosing brackets:

In the above $static_var is initialized before the subroutine "foo" but can be changed as needed inside the "foo" function, but it is invisible to the rest of the program. -------------------------------------------------

You don't want to put quotes around scalars like you have in the array. Quotes are for creating strings and can cause very hard to find bugs in perl programs when used improperly. In your program it will work fine but it is inefficient and as I said, has the potential to introduce bugs. Do it like this:

Loading 50 separate files via use or require is definitely the wrong approach.

You need no more than 3 files, 1 config file that holds the base info for the 50 plans, 1 module that uses that config file as its input and has routines that handle the calculations, and then finally the script that puts it all together.

The strange thing I found with using require instead of use is that it would process the first client then come up with an error message however it did accept a variable as an argument by doing eval "require $acp"; unfortunately only for 1 client

Thanks for your input, I did it that way when I first wrote the program years ago in bash.

However I found each plan needs to be in a separate file otherwise there is to much risk of corruption if something changes or you need to add another plan.

You also have much more freedom of control where a plan is still active but not current i.e. you don't sign up new clients to that plan.

Finally the way I have structured the corresponding data bases and support files would require another 2 months of work to change.

There are lots of other reasons as well.

What I really need is something like PHP include where I can pass the variables easily and the code in the subroutine behaves as if its part of the main program. Additionally its easy to call different subroutines with a variable.

I just didn't realise it would be this complicated in Perl when I planed it out. Although its probably very simple in reality I am just not far along the leaning curve to understand how to do it.

The problem I am facing is the same as leaning a language like english, I know a few words like hello goodby and "where is the toilet" but to solve this little problem it looks like I have to know the whole blasted dictionary - backwards. Which I understand is my problem

Fortunately I have found a way around this issue and its working fine its just not elegant and I want it to work and look good as well.

Yes, if you go that route you need a block of if/elsif (or switch style statements). But 50 if/elsif's is not unusual in a script where there are many user options. Its been a while since I wrote or helped write a big program but I remember having 100+ blocks of conditionals for a script to determine what actions to take and which modules to load. -------------------------------------------------

# now connect and get a database handle my $dbh = DBI->connect($dsn, $user, $pass) or die "Canít connect to the DB: $DBI::errstr\n";

#first get all the phone numbers I dont know if there is any value in getting this months numbers as we only need to get a value for last month #because we are working out the costs for last month and adding the plan costs to overusage - #numbers that appear in this months stuff should be different in that they are processed with the join date and the prorata is calculated

my $username=$row[1]; my $udab=$row[4]; my $tplan=$row[0]; #if no user report #print "$username \n"; #if exists delete orphan if (!$username) { #you will need to delete the file or the contents on each run because the numbers that existed in the file that dont exist now have been dealt with and secondly numbers would be appended on each run and that be bad

#you need to nut this out udab is the last time this account was paid #SO you can do MUCH MORE HERE like overdue and never paid come to mind also if its 0 or "" you should put in $joined and work out all the payments from then till now and send an email so we are aware there is an issue

#if it does not exist we REALLY want to know about it so do something here

if (-e $fexist) { plancontroler("$outdatamb"); } }

And this is the apc.pm subroutine I am calling

#!/usr/bin/perl -w package apc; #:defines the name of the package (Like twig) use Exporter; #use this package to make it work @ISA = ('Exporter'); #I think this is some predefined array that you put this package into @EXPORT = ('plancontroler'); #it exports the function below

Please use the code tags especially when posting blocks of code like you have in this post. The code tags help to separate your code from your comments and retains the formatting/indentation.

First, you need to realize that use and require are executed at different times; use statements happen at compile time (before any var assignments) and require statements happen at runtime. So, if you plan on using a var in the statement you need to use a require statement. Actually there is another option, but I don't want to add more confusion.

Another difference is that a use statement will import the plancontroler() subroutine, but the require statement won't, so you'll need to do an explicit import.

Code

my $module = 'apc.pm'; require $module; apc->import;

You should not use lowercase names for your modules. By convention, lowercase names are reserved for pragmas (which are special compiler directive modules). Module names should be in Titlecase.

Instead of using the -w switch, it's better to use the warnings pragma and you should also be using the strict pragma in every script.

There's no need to explicitly load DBD::mysql. The DBI module loads the DBD:: module specified in the connect statement via a require statement.

It's better to use a lexical var for the filehandle and the 3 arg form of open. So, this:

Why are you using $found += 1; in the while loop, but fail to use that var latter in the script? If you really do need that counter, you should be using the built-in $. var which holds the current line number of the file you're looping over.

You should check the return code from every open call and take proper action if the open call fails.

Your explanations answer a lot of the things I could not figure out by myself.

I should have reread the Perldoc on require and tried a few examples before asking the question. But I doubt I would have twigged that one is compiled and the other is not for another few months.

I grabbed the code from my current program written in bash and worked my way through each module rewriting it in Perl and after a few rewrites it got a bit messy and that is why the $found += 1 is there - I forgot to remove it.

below are a couple of the plan subroutines with out the headers and footers for making them work as subroutines.