Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hello Monks,

I'm trying to re-write an old program of mine and leave my perl-4-style (.pl) modules behind and use proper perl 5 modules and I'd really appreciate some help here.
The main problem I'm facing at this stage is working out how to make the variables and subroutines available between all loaded modules, as was the case when modules were "required".
My idea for the structure of the software was to create one main "switch" program which would call on the routines contained in the "used" modules:
index.pl (web-based main program called)
My::Database (connect to MySQL)
My::Globals (load in system-wide globals)
My::Package_A (some general routines)
My::Package_B (more general routines)
...

For example, My::Database exports a connection to the database with variable $dbh. My::Globals exports a hash "%globals" containing system path information, general settings etc, etc. Both $dbh and %globals are of course readily available in index.pl in their short form.

The problem is that neither $dbh or %globals are available in My::Package_A or My::Package_B without using the full strings $My::Database::dbh and %My::Globals::globals. The same applies to subroutines sharing between modules.

That's a lot of typing each time they're needed, and this is part of what I'm trying to avoid.
For example if My::Package_B were to compose a HTML page, then there would be ridiculously many occurrences of <img src="$My::Globals::globals{'image_directory'}/image.jpg">...
with just as many typos.
Having already done some searching on sharing globals between modules it would seem that it's not done, but frankly I'm struggling to find a suitable (readable) solution.

Am I being lazy here or is this the sort of thing everyone just "deals with" when creating packages?

Many thanks.

Example code (greatly simplified for illustration)
index.pl -------- #!/usr/bin/perl use strict; use vars qw($dbh %sth %config %globals); use CGI qw(:standard); use DBI; use My::Database; use My::Globals; use My::Package_A; connectDB(); my $content = "dbh = $dbh<br>"; outputHTML($content); exit; ----------------------- package My::Database; use strict; use base 'Exporter'; our $VERSION = '1.0'; our @ISA = ('Exporter'); our @EXPORT = qw(connectDB $dbh); use vars qw($dbh); sub connectDB { $dbh = DBI->connect("DBI:mysql:database='database_name';host='host +_name'", 'user_name', 'password', {RaiseError => 1, AutoCommit => 0}) +; } 1; ---------------------------------- package My::Globals; use strict; use base 'Exporter'; our $VERSION = '1.0'; our @ISA = ('Exporter'); our @EXPORT = qw(%globals); use vars qw(%globals); sub load_globals { %gloabls = (); $globals{'image_directory'} = '/path/to/image/directory'; } 1; --------------------------- package My::Package_A; use strict; use base 'Exporter'; use CGI qw(:standard); our $VERSION = '1.0'; our @ISA = ('Exporter'); our @EXPORT = qw(outputHTML); sub outputHTML { my ($data) = $dbh->selectrow_array(qq|SELECT data FROM table WHERE + 1|); my $html = shift; print header; print <<HTML; <head> </head> <body> <p>$html</p> <p><img src="$globals{'image_directory'}/image.jpg"></p> <p>$data</p> </body> </html> HTML } 1;

Replies are listed 'Best First'.
Re: Sharing Variables and Routines between modules
by Marshall (Canon) on Nov 01, 2010 at 21:03 UTC
    I agree with happy.barney about dependencies. I would not put other dependencies inside of My_Globals.pm.

    Both $dbh and %globals are of course readily available in index.pl in their short form.

    Maybe there is a misunderstanding here. If you define %globals in some package, and export that name, it exists anywhere that you have used the My_Globals.pm package and imported %globals (below it is exported implicitly to all "users").

    You take out the my %globals=(...) stuff from index.pl. That initialization code now lives in the Globals.pm package. $globals{'a'}, I guess what you call the "short form" works in index.pl after it uses My_Globals.pm.

    #/usr/bin/perl use strict; use warnings; use My_Globals; print "global a = $globals{'a'}\n"; __END__ prints: global a = 1 =========== file My_Globals.pm ======== #!/usr/bin/perl use strict; use warnings; package My_Globals; use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION); use Exporter; our $VERSION=1.0; our @ISA = qw(Exporter); our @EXPORT = qw(%globals); our @EXPORT_OK = qw(); our %globals = ( a => 1, b =>2); 1;
Re: Sharing Variables and Routines between modules
by happy.barney (Friar) on Nov 01, 2010 at 17:32 UTC
    add use My::Globals (and so) to every package that use it. Otherwise you will be in trouble if you forgot to use it in main script :-)
      I thought about that but then I end up cross-using modules.

      package My::Database;
      use My::Globals;
      use My::Package_A;
      use My::Package_B;
      ------------------
      package My::Globals;
      use My::Database;
      use My::Package_A;
      use My::Package_B;
      --------------------
      etc.etc
      Then when I want to add My::Package_C I have to go through every single module and add it to the list...
        Globals requires Package_A ?
        package My::Package_A; use My::Globals; use My::Database;
        and so on ...
Re: Sharing Variables and Routines between modules
by scorpio17 (Canon) on Nov 02, 2010 at 13:20 UTC

    I suggest you try using CGI::Application. The database handle will be accessible to any run mode (web page) by using $self->dbh, and you can use $self->param() to share data instead of using globals, etc.

      Thanks for your replies all.

      Having read the pod for CGI::Application gave me some valuable insight about a better way to reach my goals.

      The best approach I've been able to come up with so far is this:

      Write basic framework "instance" scripts: index.pl, admin.pl etc.etc.
      Each script uses My_Common which contains the bulk of the software's routines.
      My_Common uses My_Database and My_Globals
      My_Database and My_Globals export their methods to MyCommon which in turn exports these to the instance script.

      The result: shared variables and routines.
      $global{'image_path'} stays in this form as does $dbh for the database handle, and both are available in index.pl and My_Common

      Every new instance script simply uses My_Common, and if I decide to create other modules, these can be simply used by My_Common and I'm good to go again.

      Thanks again.