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

Hi people

The saga continues! In recent weeks, I've been finding most of the bugs within my code thanks to help and advice from the more amicable monks out there. Once again I'd like to call upon their know-how.

There's no point in explaining the application - suffice to say it's huge! But, having been guided towards use strict; and debugging via FatalsToBrowser amongst other suggestions, I now would like to do the following; 'require'ing a config.lib file which contains about 20 variables which (in my opinion) should be global to the whole thing (for example, default language, directory locations, database files, etc...). Some threads here have discussed the pros/cons of using global/local/my/our declarations - the variables which I wish to declare will not be changed by anything; once they're set, they're set! So there's no fear of a bug developing somewhere withing the 100,000's of lines of code!

Is it still necessary to specify each variable within the (for example) index.cgi script using use vars qw($var1 $var2 etc...); or is there a way to declare them when the file is 'require'd ? Or am I missing the point seeing as though the snippet I'm using suggests :-

# Ensure all fatals go to browser during debugging and set-up # Comment this BEGIN block out on production code for security BEGIN { $|=1; # Flush the buffers (as they say!) print "Content-type: text/html\n\n"; use CGI::Carp('fatalsToBrowser'); }

This also has other implications for me - the index.cgi file is the main login aswell, so not only are there system-wide settings (which will not change), there are also several variables set when a user logs in, depending upon their permissions, their preferred language, etc... I was creating these dynamically, but can't do that now using strict!

Thanks to all those who have helped me out thus far (you know who you are!)

Regards as always - Richard.

Replies are listed 'Best First'.
Re: strict, debug and global variables
by Aristotle (Chancellor) on Sep 16, 2004 at 22:35 UTC

    Yes, you have to declare the variables. The compiler must know about the variables at compile time so it knows not to complain, and the file you require is not loaded until runtime. A solution to that might be to write a configure module that exports the variables in question.

    As for the code block you show, I don't know why that should be commented out in production code. The only thing I see that should only be used during development is fatalsToBrowser — but all the rest applies, including use CGI::Carp; itself, since that will make your server error logs more informative.

    Makeshifts last the longest.

Re: strict, debug and global variables
by freddo411 (Chaplain) on Sep 16, 2004 at 23:48 UTC
Re: strict, debug and global variables
by davido (Cardinal) on Sep 17, 2004 at 00:03 UTC

    You can create a package with package global variables in it, and get at those variables using their fully-qualified name, like this:

    First, just name this one MyConfig.pm:

    package MyConfig; use strict; use warnings; our $testvar = "Hello world."; 1;

    And now in MyScript.pl:

    #!/usr/bin/perl use strict; use warnings; use MyConfig; print $MyConfig::testvar, "\n";

    Using the fully qualified variable name means you won't be exporting it directly into your main script's namespace, you'll just be accessing the configuration package's namespace. That's a pretty easy way to do it.


    Dave

      The drawback to fully qualified names is, of course, that you don't get the typo checking otherwise offered by strict.

      Makeshifts last the longest.

        Pick your poison I guess. There are a lot of ways to deal with configuration data. The OP seems to want globals, and I figured at least with fully qualified variables at least he eliminates namespace pollution.

        There are many many other alternatives too though:

        • Config::General which grabs configuration data from a file and plops it into a hash. I happen to like the hash approach, though to your strict point, a hash's elements also are not subject to the helping hand of strictures.
        • Using a package and accessing its configuration variables via their fully qualified names. It doesn't pollute package main's namespace, but also doesn't result in the strictures checking.
        • Exporting from a configuration module / importing into the main script. While this will benefit from the use strict; assistance, it will also pollute package main's namespace. If you don't have absolute control over the configuration file, it would be easy to inject trouble this way.
        • Use Data::Dumper, or Storable to read in the configuration information.
        • Put the configuration information into a package, and export a set of accessor funtions to get at the configuration info. That way you're not actually touching the configuration variables, but accessing their data through sanitized accessors. A well behaved accessor should react appropriately when the caller tries to access configuration data that isn't part of the package.
        • A config object... This method could automate reading the data in from some source, and provide methods for retrieving the data. ...similar to the previously-mentioned proposal, but has the potential of creating a simpler interface through the magic of Object Oriented abstraction.
        • And about a million other approaches, some better than others. ;)

        Dave

Re: strict, debug and global variables
by ihb (Deacon) on Sep 16, 2004 at 22:38 UTC

    is there a way to declare them when the file is 'require'd

    Yes, there is, if you can use() the module. It requires that you write your own &import routine.

    use vars (); sub import { my $pkg = caller; no strict 'vars'; vars::->import(map { /(.)(.*)/; "$1$pkg\::$2" } qw/ $var1 $var2 $e +tc /); }
    If you export things with the Exporter module you need to handle that:
    use vars (); sub import { __PACKAGE__->export_to_level(1, @_); my $pkg = caller; no strict 'vars'; vars::->import(map { /(.)(.*)/; "$1$pkg\::$2" } qw/ $var1 $var2 $e +tc /); }

    Exporter does this for you if you export the variables, so that's a much easier way...

    ihb

    Read argumentation in its context!

Re: strict, debug and global variables
by meetn2veg (Scribe) on Sep 17, 2004 at 05:45 UTC
    Thanks to all who've replied so far! Your comments/opinions are all helping!

    However, I've just come across the same situation as before, and I still think it's a memory issue with the server!?!

    Situation: library.cgi file contains the usual. One sub is this:

    ##################################################### sub build_input_textbox{ ##################################################### my ( $INPUT_type,$INPUT_name,$INPUT_value,$INPUT_class,$INPUT_styl +e,$INPUT_js,$INPUT_max_length ) = (shift,shift,shift,shift,shift,shif +t,shift); my $inbox = qq¿<INPUT TYPE="$INPUT_type" NAME="$INPUT_name" ¿; $inbox .= ($INPUT_value ne "") ? qq¿VALUE="$INPUT_value" ¿ : "" ; $inbox .= ($INPUT_class ne "") ? qq¿CLASS="$INPUT_class" ¿ : "" ; $inbox .= ($INPUT_style ne "") ? qq¿STYLE="$INPUT_style" ¿ : "" ; $inbox .= ($INPUT_max_length ne "") ? qq¿MAXLENGTH="$INPUT_max_len +gth" ¿ : "" ; $inbox .= ($INPUT_js ne "") ? qq¿$INPUT_js ¿ : "" ; $inbox .= qq¿ >\n¿; return $inbox; }

    At the end of one of my scripts, I have the following:

    $my_buttons .= build_input_textbox("hidden","m0","$m0"); $my_buttons .= build_input_textbox("hidden","m1","$m1"); $my_buttons .= build_input_textbox("hidden","do","save"); $my_buttons .= build_input_textbox("hidden","act","$act"); $my_buttons .= build_input_textbox("hidden","site_uid","$SITE_UNIQ +UE_ID"); $my_buttons .= build_input_textbox("hidden","what","new_contact");

    Running under strict with fatalsToBrowser etc..., the script does not terminate, there is no error, nothing in the error_log file, $my_buttons has been declared, the values passed ($m0, $m1 etc.) are OK, and the only HTML that's received stops at the <body> tag. Yet if I comment out 5 lines - any 5 lines will do, the script works! Comment out 4 lines, it fails! Blank screen!

    Am I really being stupid on this one?!? Could it be something other than a server issue?

    From a human point of view, I suppose there is quite a lot going on further up the script. The way I'm doing things is to assign output to $vars, then load a template file and s/<MY_TAG\>/$my_tag/g; substitute the necessary bits. Right or wrong, thats the way I'm doing it!

    Hense this is why I think it's a server issue - my code works up to a point. Add a bit more onto the end of a variable, and it fails! :-|

    Clues anyone?