For Programmers: Free Programming Magazines  


Home > Archive > PERL CGI Beginners > October 2006 > Including a file with common variables...









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author Including a file with common variables...
Shawn Hinchy

2006-10-08, 3:55 am

Hello all,

I am writing many cgi scripts and need to have the same variables =20
included in each of them. I was going to put all these 'global' =20
variables in a separate file that could then be included in the top of =20
each cgi script. I am already doing a similar thing with functions =20
and requiring that .pl file. The problem is that I cannot get the =20
variables to show in the main cgi script.

To include the subroutines I do this:

require './utilities.pl';

In the utilities.pl file I have this:

#!/usr/bin/perl -wT
sub foo {}
1;

I tried adding the variables to the top of this file, declared as my, =20
local and our. None of them worked.

I tried making a separate variables.pl file such as:

my globalvariable =3D '';

which I then tried to include using:

require './variables.pl';
use './variables.pl';
do './variables.pl';

None of these worked. I read the perldoc for each of these functions =20
and 'do' looks like the best candidate but I cannot get it to work. I =20
am sure it is something small I am overlooking.

Any suggestions?

Thanks,

Shawn
--------------------
Shawn Michael Hinchy
shawn@hinchy.net





Mumia W.

2006-10-08, 3:55 am

On 10/07/2006 10:27 PM, Shawn Hinchy wrote:
> Hello all,
>
> I am writing many cgi scripts and need to have the same variables
> included in each of them. I was going to put all these 'global'
> variables in a separate file that could then be included in the top of
> each cgi script. I am already doing a similar thing with functions and
> requiring that .pl file. The problem is that I cannot get the variables
> to show in the main cgi script.
>
> To include the subroutines I do this:
>
> require './utilities.pl';
>
> In the utilities.pl file I have this:
>
> #!/usr/bin/perl -wT
> sub foo {}
> 1;
>
> I tried adding the variables to the top of this file, declared as my,
> local and our. None of them worked.
>
> I tried making a separate variables.pl file such as:
>
> my globalvariable = '';
>


Use package variables for this purpose:

our globalvariable = '';


> which I then tried to include using:
>
> require './variables.pl';
> use './variables.pl';
> do './variables.pl';
>
> None of these worked. I read the perldoc for each of these functions
> and 'do' looks like the best candidate but I cannot get it to work. I
> am sure it is something small I am overlooking.
>
> Any suggestions?
> [...]


Use package variables. Variables created with "my" will be restricted to
either file scope or block scope.


Ovid

2006-10-08, 3:55 am

--- Shawn Hinchy <shawn@hinchy.net> wrote:

> Hello all,
>
> I am writing many cgi scripts and need to have the same variables
> included in each of them. I was going to put all these 'global'
> variables in a separate file that could then be included in the top
> of each cgi script.


I've seen people do this many times and it leads to clunky,
hard-to-debug systems. Globals should be avoided. Because they wind
up being spread throughout your code, it's easy for them to get altered
in one spot and not be able to figure out who altered them. Plus,
programmers can sometimes get about where those variables come
from, making bugs with them more difficult to figure out. Also, any
functions which rely on the existence of globals becomes harder to
refactor/use (e.g., moving it to a module which doesn't have the
globals causes things to break).

Sometimes you *do* have data which everything needs to know about.
Here are some suggestions:

1. Put those variables in constants or use the 'Readonly' module from
the CPAN.
2. If a function needs one of them, pass it as an argument.
3. Maybe put the variables in a module where you need to explicitly
request them via Exporter.
4. Alternately, do number 3 with a config file.

> To include the subroutines I do this:
>
> require './utilities.pl';


This is Perl 4 syntax. Actually, it's Perl 3. Please don't use that.
http://www.oreillynet.com/onlamp/bl...ng_perl_3.html.
I know there's still a lot of stuff out there which teaches that and
I'm sorry you've learned from that, but the sooner you avoid that, the
better.

> In the utilities.pl file I have this:
>
> #!/usr/bin/perl -wT
> sub foo {}
> 1;


Rename that to something like 'My::Utilities' and try giving Exporter a
try, or any of its competitors. Here's an example:

package My::Utilities;

use strict;
use warnings; # if your version of Perl supports it

use base 'Exporter';
use vars qw(
@EXPORT_OK
$BAD_GLOBAL_VAR
some_sub
);

@EXPORT_OK = qw(
$BAD_GLOBAL_VAR
COMPANY_NAME
some_sub
some_other_sub
);

$BAD_GLOBAL_VAR = 'try to avoid globals';
use constant COMPANY_NAME => 'Acme, Inc';

sub some_sub {}
sub some_other_sub {}
sub cant_get_exported {}

1;

And in the calling code:

#!/usr/bin/perl -T

use strict;
use warnings;
use lib 'path/to/your/modules';

use My::Utilities qw(COMPANY_NAME some_sub $BAD_GLOBAL_VAR);

With that, you have cleaner namespaces. You only pollute your
namespace with the specific subroutines or constants you're asking for.
It's obvious where things are coming from.

One problem with 'utilities' modules is that they tend to get very
bloated and programmers start shoving a bunch of stuff in them with no
rhyme or reason. Then, when you do "require './utilities.pl'", you
wind up getting a bunch of extra subroutines and if you make the
mistake of reusing *any* subroutine name in any of your files, you can
get very mysterious errors, particularly if you forget to turn warnings
on (which, to your credit, you did not :)

I've worked on systems like this and they're not fun. I recently had a
problem on a legacy system like this where I found a sub not declared
in the code. Then I found it was not declared in any of the code which
was 'require'd. Then I found it wasn't in any of the modules *they've*
required. I found it in a module which one of the *last* one's
required. Of course, I first tried grepping through the code, only to
find that the function name in question was reused in a number of
places, so that didn't help, either. It was very frustrating to work
on. The system uses some of the "features" you're asking for help
with. Please don't make the same mistakes :)

Cheers,
Ovid

--

Buy the book -- http://www.oreilly.com/catalog/perlhks/
Perl and CGI -- http://users.easystreet.com/ovid/cgi_course/
Shawn Hinchy

2006-10-08, 6:55 pm

Quoting Ovid <publiustemp-beginnerscgi2@yahoo.com>:
> --- Shawn Hinchy <shawn@hinchy.net> wrote:
>
>
> I've seen people do this many times and it leads to clunky,
> hard-to-debug systems. Globals should be avoided. Because they wind
> up being spread throughout your code, it's easy for them to get altered
> in one spot and not be able to figure out who altered them. Plus,
> programmers can sometimes get about where those variables come
> from, making bugs with them more difficult to figure out. Also, any
> functions which rely on the existence of globals becomes harder to
> refactor/use (e.g., moving it to a module which doesn't have the
> globals causes things to break).
>
> Sometimes you *do* have data which everything needs to know about.
> Here are some suggestions:
>


Thank you Mumia and Ovid. I appreciate both of your responses. I =20
agree with you Ovid, you make some very good points. The point I =20
forgot to include is that these variables are actually =20
configuration-type constants. I misnamed them by calling them =20
variables.

> 1. Put those variables in constants or use the 'Readonly' module from
> the CPAN.
> 2. If a function needs one of them, pass it as an argument.
> 3. Maybe put the variables in a module where you need to explicitly
> request them via Exporter.
> 4. Alternately, do number 3 with a config file.
>


I think maybe the best solution may be to use the Readonly module. It =20
was unclear to me, however, exactly how to use it from the readme. =20
I'll have to play around with it.

I have been avoiding modules because they seemed to complicate things =20
a bit and I guess I don't know exactly how they work. Besides, if I =20
make a module, don't I have to install it? I don't think I have =20
access to install my own modules on my hosting server. I guess it's =20
time to do some more reading...

>
> This is Perl 4 syntax. Actually, it's Perl 3. Please don't use that.
> http://www.oreillynet.com/onlamp/bl...ing_perl_3.htm=

l.
> I know there's still a lot of stuff out there which teaches that and
> I'm sorry you've learned from that, but the sooner you avoid that, the
> better.
>
>
> Rename that to something like 'My::Utilities' and try giving Exporter a
> try, or any of its competitors. Here's an example:
>
> package My::Utilities;
>
> use strict;
> use warnings; # if your version of Perl supports it
>
> use base 'Exporter';
> use vars qw(
> @EXPORT_OK
> $BAD_GLOBAL_VAR
> some_sub
> );
>
> @EXPORT_OK =3D qw(
> $BAD_GLOBAL_VAR
> COMPANY_NAME
> some_sub
> some_other_sub
> );
>
> $BAD_GLOBAL_VAR =3D 'try to avoid globals';
> use constant COMPANY_NAME =3D> 'Acme, Inc';
>
> sub some_sub {}
> sub some_other_sub {}
> sub cant_get_exported {}
>
> 1;
>
> And in the calling code:
>
> #!/usr/bin/perl -T
>
> use strict;
> use warnings;
> use lib 'path/to/your/modules';
>
> use My::Utilities qw(COMPANY_NAME some_sub $BAD_GLOBAL_VAR);
>
> With that, you have cleaner namespaces. You only pollute your
> namespace with the specific subroutines or constants you're asking for.
> It's obvious where things are coming from.
>


Is that a package or a module? I will give that a try after doing a =20
little more reading.

> One problem with 'utilities' modules is that they tend to get very
> bloated and programmers start shoving a bunch of stuff in them with no
> rhyme or reason. Then, when you do "require './utilities.pl'", you
> wind up getting a bunch of extra subroutines and if you make the
> mistake of reusing *any* subroutine name in any of your files, you can
> get very mysterious errors, particularly if you forget to turn warnings
> on (which, to your credit, you did not :)
>
> I've worked on systems like this and they're not fun. I recently had a
> problem on a legacy system like this where I found a sub not declared
> in the code. Then I found it was not declared in any of the code which
> was 'require'd. Then I found it wasn't in any of the modules *they've*
> required. I found it in a module which one of the *last* one's
> required. Of course, I first tried grepping through the code, only to
> find that the function name in question was reused in a number of
> places, so that didn't help, either. It was very frustrating to work
> on. The system uses some of the "features" you're asking for help
> with. Please don't make the same mistakes :)
>
> Cheers,
> Ovid


Thank you Ovid, I appreciate you taking the time to respond. =20
Hopefully someone else will learn from my question as well.

So, knowing that I am trying define system-wide constants, would you =20
personally recommend the Readonly module or to use my own module or =20
package? I need the constants to be available to multiple scripts.

Thanks!

Shawn

Mumia W.

2006-10-08, 6:55 pm

On 10/08/2006 12:15 PM, Shawn Hinchy wrote:
>
> Thank you Mumia and Ovid. I appreciate both of your responses. I agree
> with you Ovid, you make some very good points. The point I forgot to
> include is that these variables are actually configuration-type
> constants. I misnamed them by calling them variables.
> [...]


If you want to put some constants in a module, one of the many options
is to use the "constant" and "Exporter" modules like so:

# file: AppConstans.pm
use strict;
use warnings;
package AppConstants;
use base 'Exporter';
use constant DB_HOST => 'my.host.example.com';
use constant DB_USER => 'my_user';
use constant DB_PASS => 'my_pass';
use constant LIST_OPTIONS => {
recursive => 1,
classes => 'd,s',
};

our @EXPORT = qw(DB_HOST DB_USER DB_PASS LIST_OPTIONS);

1;

__END__


In your main program you might do this:

use AppConstants;
....
my $dsn = "DBI:mysql:database=mydb;hostname=" . DB_HOST;
my $dbh = DBI->connect($dsn, DB_USER, DB_PASS);
....

Here is some useful documentation:
perldoc constant
perldoc Exporter
perldoc base
perldoc perlmod

P.S.
It's usually best to not export things by default, but I decided to make
this example simple.

Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com