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

I know I can use a global variable from my main program in a function in a package: $main::some_var

However, I usually use strict and, when I do that, $main::some_var is not available, even within the main program. I know I can turn off "use strict", even if only temporarily, but I have the feeling there must be some better way????

...and, yes, I try to stay away from globals, but it seems the way to go for something I'm writing...

Thanks for any help!
Apprentice

Replies are listed 'Best First'.
(Ovid) Re: package identifiers and scope question
by Ovid (Cardinal) on Sep 05, 2001 at 21:18 UTC

    I can not think of a situation in which turning on strict would remove access to global variables. They just don't have anything to do with one another. Could you reduce your code to a minimal test case and post it here? I have the feeling that you are missing something.

    Also, you may wish to consider 'our' or 'use vars' for globals. They allow you to use globals without giving up the virtues of strict. You can read about the differences between 'our' and 'my' if you think that will clear things up for you.

    My burning question, though, is why you feel that a global variable is "the way to go"? Seldom is a global variable the best option for something. If you explain your reasoning, perhaps we can suggest a better option?

    Cheers,
    Ovid

    Vote for paco!

    Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

      Thanks, Ovid, the tutorial was very useful.

      OK, so you can stop burning and I can gain some enlightenment:

      I am writing a cgi to run a website using a mysql database. I have to pass various objects around (cgi query object, database handle, et.al.) and it is tiresome to have to explicitly pass these things through multiple functions. I have a main program, a "web pages module", and a "utilities module" to keep the code logically separated. It isn't a huge application and I'm the only one working on it (for myself, not for a company), so it seemed easiest to use a very few global variables. However, if you can suggest a better way, I'm all ears...er...eyes!

      Thanks!
      Apprentice

        apprentice, I understand your reasoning, but this is an excellenent example of why you don't want to use global variables. You may want to read about good programming practices and how you can get bit violating them.

        The larger an application grows, the more items tend to need access to global variables. While I realize that you don't want to pass around a bunch of different objects and variables, it's very, very easy to lose track of where you're instantiating them, changing them, etc. However, if code is written tightly enough, I find that there's less passing around of these objects than one would think. Usually, you're passing the data gotten from the objects than the objects themselves.

        What would be the best way for you to approach this would vary greatly upon your application needs. I don't know what you're use you're putting your CGI objects to, for example. Let's say, for example, that you're only using the CGI object for the CGI::param() method. You could package all of your objects into an "application" object and just pass that around instead of all of the objects and data. What follows is a much different solution from what others suggest and I'm not wild about it, but I though I would toss it out there in the spirit of TIMTOWTDI.

        package My::Application; use strict; use DBI; use CGI; sub new { my $class = shift; my $q = CGI->new; my %data = map { $_, [ $q->param($_) ] } $q->param; my $href = { _dbh = connect_routine(), _data = \%data }; bless $href, $class; } sub form_data { # remember that all data returned from this is tainted!!!! my ( $self, $item ) = @_; if ( ! exists $self->{ _data }{ $item } ) { return undef; } elsif ( wantarray ) { return @{ $self->{ _data }{ $item } }; } else { return $self->{ _data }{ $item }[0]; } } sub get_user_info { my ( $self, $id ) = @_; # Note the placeholder .. greater security my $sql = "SELECT first, last FROM users WHERE id = ?"; my $sth = $self->{ _dbh }->prepare( $sql ); my $rc = $sth->execute( $id ); . . . }

        I think you get the idea from the above (very untested) example. With that, you encapsulate all application specific objects and data into one object and just pass that around. The objection I have to my method is that now you're mixing cheese and Wednesday. Frankly, I don't like the idea of mixing form-handling code and database code in one object, but this is just a rough idea to show you how it's done. On the other hand, if you reframe it with the idea that you're gathering all application specific data retrieval into one module, then I think it's justifiable.

        use strict; use My::Application; my $app = My::Application->new; # it's transparent to the programmer, but this is getting # the data from the submitted form data my $user_id = $app->form_data( 'user_id' ); # again, we have application specific data, but from # the database instead of the user form my $user_details = $app->get_user_info( $user );

        Cheers,
        Ovid

        Vote for paco!

        Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

        Objects. Think Objects.

        The stuff you're passing around won't be global, it will be the instance data.

        —John

Re: package identifiers and scope question
by dragonchild (Archbishop) on Sep 05, 2001 at 22:19 UTC
    If you're having to pass objects around a lot, you didn't build your objects right. One thing I'm starting to realize while building a OO game is that objects don't have attributes so much as they have actions. An object doesn't so much have something as it does something.

    If you think about it that way for a few days, it will become clearer. (I had a question about this exact topic yesterday and realized that every reason I had to make something global was really just me not realizing the power of OO in my situation.)

    ------
    We are the carpenters and bricklayers of the Information Age.

    Vote paco for President!

Re: package identifiers and scope question
by apprentice (Scribe) on Mar 24, 2002 at 19:50 UTC
    I finally figured it out.

    What I really wanted to do was to have my various modules use $main::DEBUG to set their own package global $DEBUG variable.

    The problem turned out to be that, even though I set the variable in main before 'use'ing the modules (packages), it wasn't available at compile time before the modules (packages) were loaded.

    The answer was to put the variable in main in a BEGIN block:
    BEGIN { our $DEBUG = 1; }
    The variable was then available in the modules (packages):
    my $DEBUG = $main::DEBUG; <code> <i>However</i>, $DEBUG was then not available <i>within</i> main! <br><br> I don't know the reason for that, but I resolved it by doing this furt +her down in main: <code> my $DEBUG = $main::DEBUG;
    It worked fine from there.

    "Peace, love, and Perl...well, okay, mostly just Perl!" --me

    Apprentice
Re: package identifiers and scope question
by idnopheq (Chaplain) on Sep 05, 2001 at 21:15 UTC
    Can you show your source? It may help with a specific solution. W/o it, I'd say pass those as args to your subs and catch the return values.

    HTH
    --
    idnopheq
    Apply yourself to new problems without preparation, develop confidence in your ability to to meet situations as they arrise.