How to use global variables in perl correctly

I am new to Perl. I am trying to figure this out by writing several programs. Detecting in perl makes it difficult for me.

I wrote the following:

use 5.16.3; use strict; use Getopt::Long; Getopt::Long::Configure(qw(bundling no_getopt_compat)); &ArgParser; our ($sqluser,$sqlpass); $sqluser="root"; $sqlpass="mypassword"; sub ArgParser { print "Username is ".$sqluser." Password is ".$sqlpass."\n"; my $crt=''; my $delete=''; GetOptions ('create|c=s' => \$crt, 'delete|d=s' => \$delete ); if ($crt) { &DatabaseExec("create",$crt); } elsif ($delete) { &DatabaseExec("delete",$delete); } else { print "No options chosen\n"; } } sub DatabaseExec { use DBI; my $dbname=$_[1]; print "Username is ".$sqluser." Password is ".$sqlpass."\n"; my $dbh = DBI->connect("dbi:mysql:", $sqluser,$sqlpass); my $comand=$_[0]; if ($_[0] eq "create") { my $db_com="create database ".$dbname; print 1 == $dbh->do($db_com) ? "Database created\n":"An error occured while creating database. Maybe it exists?\n"; #print "Executing: ".$db_com."\n"; } elsif ($_[0] eq "delete") { my $db_com="DROP DATABASE ".$dbname; #print "Executing: ".$db_com."\n"; print 1 == $dbh->do($db_com) ? "Database deleted\n":"An error occured while creating database. Maybe it exists?\n"; } } 

As far as I understand, ours would declare them global variables for using the main code and routines. However, this gives the following result:

 #~/perlscripts/dbtest.pl -c hellos Use of uninitialized value $sqluser in concatenation (.) or string at /root/perlscripts/dbtest.pl line 20. Use of uninitialized value $sqlpass in concatenation (.) or string at /root/perlscripts/dbtest.pl line 20. Username is Password is Use of uninitialized value $sqluser in concatenation (.) or string at /root/perlscripts/dbtest.pl line 44. Use of uninitialized value $sqlpass in concatenation (.) or string at /root/perlscripts/dbtest.pl line 44. Username is Password is DBI connect('','',...) failed: Access denied for user 'root'@'localhost' (using password: NO) at /root/perlscripts/dbtest.pl line 45. Can't call method "do" on an undefined value at /root/perlscripts/dbtest.pl line 50. 

I would not want to pass them as arguments to sub and would rather use them as global variables. Can someone help me identify my misunderstanding?

+4
source share
3 answers

Your variables are not declared when calling the subroutine:

 &ArgParser; # subroutine call our ($sqluser,$sqlpass); # declaration $sqluser="root"; # assignment $sqlpass="mypassword"; 

To use these global variables inside a routine, place the routine after the variable declaration.

However, using global variables is bad, and you should avoid it whenever possible. You can do this, for example:

 my $sqluser = "root"; my $sqlpass = "mypass"; ArgParser($sqluser, $sqlpass); # you should not use & in subroutine calls 

And then inside the routine:

 sub ArgParser { my ($sqluser, $sqlpass) = @_; ... 

Thus, your variables are beautifully encapsulated and safe from accidental manipulation.

As for the ampersand & in a subroutine call, this is described in perldoc perlsub :

 To call subroutines: NAME(LIST); # & is optional with parentheses. NAME LIST; # Parentheses optional if predeclared/imported. &NAME(LIST); # Circumvent prototypes. &NAME; # Makes current @_ visible to called subroutine. 
+11
source

Perl has no global variables. What is Perl:

  • Package variables.
  • Variables with vocabulary.

A package is a namespace. In Perl, the namespace is sometimes called a package. Your default name is main . For instance. This is completely legal:

 use strict; use warnings; $main::variable = "What? Where my 'our' or 'my' declaration?"; print "Look, I can print $main::variable without using 'my' or 'our'!"; 

I just prefix the variable names of the package with the package and wham! They exist!

This makes me horrified:

 use strict; use warnings; $variable = "What? Where my 'our' or 'my' declaration?"; print "I'm not going to print 'cause you're going to get a compilation error"; 

Using use strict; you must either declare the variable as our , or my , or prefix it with the name of the package in which it is located.

Batch variables are easiest to understand. Package variables are actually stored in the Perl variable structure, so they are always available after the declaration:

 use strict; use warnings; if ( 1 == 1 ) { #Yes, I know this is always true our $foo = "I have a value!"; } say "Looks like $foo has a value"; 

Lexically restricted variables are harder to understand. Basically, a variable with a lexical scope is in scope in a specific block, but out of scope as soon as you leave that block. It is also available in sub-blocks:

 use strict; use warnings; my $foo = "Foo has a value"; if ( $foo ) { #Always true my $bar = "bar has a value"; print "$foo\n"; # $foo has a value. This is a sub-block print "$bar\n"; # $bar has a value. It was defined in this block } print "$foo\n"; # $foo still has a value. print "$bar\n"; # You'll get en error here. $bar out of scope here 

Here are some suggestions:

  • You do not need to prescribe routines. It just asks for trouble.
  • If you define your variables at the beginning of your program, you can use the my variables, and they will be available in your routines, as they will still be in scope.
  • Leave & turn off routines. They cause subtle changes in the way the routine works, and these subtle changes are probably not what you want. A standard is just a subroutine call.
    • Avoid ? ... : ... especially if you don't use spaces. This makes it difficult to read your program and does not save runtime.
    • Compute a subroutine parameter into variables as soon as you call your subroutine.
  • Perl interpolates variables for you. There are many problems with Perl. It does not have a real object orientation. This is not an exception oriented language. It has a lot of coolness. One of the big advantages is that you do not need to go through all kinds of frauds to print the value of a variable. Use it and keep your head proud when you hang Python fans.
  • Use spaces to make your code easier to read.
  • Perhaps you really need constants. my will work, but the constants guarantee that these values โ€‹โ€‹will not be accidentally changed in your program.

Your code is rewritten here. Note that constants do not have a sigil in front. They usually cannot be interpolated in rows. However, if you surround them with @{[...]} , you can also interpolate them. I did this in two ways:

 use 5.16.3; use strict; use Getopt::Long; use constant { SQL_USER => "root", SQL_PASS => "mypassword", }; Getopt::Long::Configure qw(bundling no_getopt_compat); sub ArgParser { print "Username is " SQL_USER . " Password is " . SQL_PASS . "\n"; my $crt; my $delete; GetOptions ( 'create|c=s' => \$crt, 'delete|d=s' => \$delete, ); if ( $crt ) { DatabaseExec( "create", $crt ); } elsif ( $delete ) { DatabaseExec( "delete", $delete ); } else { print "No options chosen\n"; } } sub DatabaseExec { use DBI; my $comand = shift; my $dbname = shift; print "Username is @{[SQL_USER]} Password is @{[SQL_PASS]}\n"; my $dbh = DBI->connect( "dbi:mysql:", SQL_USER, SQL_PASS ); if ( $command eq "create" ) { my $db_com = "create database $dbname"; if ( $dbh->do( $db_com ) ) { print "Database created\n" } else { print "An error occured while creating database. Maybe it exists?\n"; } } elsif ( $command eq "delete" ) { my $db_com = "DROP DATABASE $dbname"; #print "Executing: ".$db_com."\n"; if ( $dbh->do($db_com) ) { print "Database deleted\n"; } else { print "An error occured while creating database. Maybe it exists?\n"; } } } 
+5
source

The classic variable coverage resource that I recommend reading is Sc-with-Show by Mark-Jason Dominus: it describes the fundamental section of the Perl variable family (batch and lexical variables) and warns of some bad practices that newbies may encounter.

0
source

All Articles