$system = system(perl -MModule::Name -e1);
if(defined(@system)) {
print "Module Exists\n";
}
else
{
print "Module does not exists\n";
}
if(defined(@system)) {
print "Module Exists\n";
}
else
{
print "Module does not exists\n";
}
`use utf8;` tells the compiler that the script is written
in UTF-8. That's all it does. `use encoding 'utf8'` tells it the srcipt is in UTF-8,
its literal strings are in UTF-8, and STDIN, STDOUT,
and DATA are in UTF-8. $ perl -Mutf8 -e'print"\x{2022}\n";' Wide character in print at -e line 1. • $ perl -Mencoding=utf8 -e'print"\x{2022}\n";' •
|
my %stats; $stats{ "name" } = "Andy Lester"; $stats{ "age" } = 31; @keys = keys %stats; # @keys is ( "name", "age" ), or maybe ( "age", "name" ) @values = values %stats; # @values is ( "Andy Lester", 31 ) or maybe ( 31, "Andy Lester" )
my %stats; $stats{ "name" } = "Andy Lester"; $stats{ "age" } = 31; my @keys = keys %stats; @keys = sort @keys; for my $key ( @keys ) { print "$key: ", $stats{ $key }, "\n"; } # Prints: # age: 31 # name: Andy Lester
my %stats; $stats{ "name" } = "Andy Lester"; $stats{ "age" } = 31; delete $stats{ "name" }; # %stats now has only one value
LASTNAME FIRSTNAME ID POSTAL_CODE AGE SEX Gauss Karl 119 19107 30 M Smith Mark 3 T2V 3V4 53 M Noether Emmy 118 19107 31 F Smith Jeff 28 K2G 5J9 19 M Hamilton William 247 10139 2 MThe names of the fields are
LASTNAME
, FIRSTNAME
, ID
,
POSTAL_CODE
, AGE
, and SEX
. Each line in the table is a
record, or sometimes a row or tuple. For example, the first row of the table represents a 30-year-old male
whose name is Karl Gauss, who lives at postal code 19107, and whose ID
number is 119.DBD::CSV
module, which we'll see later.people
. Here are examples of each of the four important kinds of queries:
SELECT firstname FROM people WHERE lastname = 'Smith'(Locate the first names of all the Smiths.)
DELETE FROM people WHERE id = 3(Delete Mark Smith from the table)
UPDATE people SET age = age+1 WHERE id = 247(William Hamilton just had a birthday.)
INSERT INTO people VALUES ('Euler', 'Leonhard', 248, NULL, 58, 'M')(Add Leonhard Euler to the table.)
DBI
(`Database Interface') module is all about. It was written by Tim Bunce.DBI
is designed to protect you from the details of the vendor libraries. It has
a very simple interface for saying what SQL queries you want to make, and
for getting the results back. DBI
doesn't know how to talk to any particular database, but it does know how
to locate and load in DBD
(`Database Driver') modules. The DBD
modules have the vendor libraries in them and know how to talk to the real
databases; there is one DBD
module for every different database.DBI
to make a query for you, it sends the query to the appropriate DBD
module, which spins around three times or drinks out of its sneaker or
whatever is necessary to communicate with the real database. When it gets the
results back, it passes them to DBI
. Then DBI
gives you the results. Since your program only has to deal with DBI
, and not with the real database, you don't have to worry about barking
like a chicken.DBI
library. You are using two databases at once. One is an Oracle database
server on some other machine, and another is a DBD::CSV
database that stores the data in a bunch of plain text files on the local
disk.DBI
, which forwards it to the appropriate DBD
module; let's say it's DBD::Oracle
. DBD::Oracle
knows how to translate what it gets from DBI
into the format demanded by the Oracle library, which is built into it. The
library forwards the request across the network, gets the results back, and
returns them to
DBD::Oracle
. DBD::Oracle
returns the results to DBI
as a Perl data structure. Finally, your program can get the results from
DBI
.DBI
in exactly the same way. DBI
would see that you were trying to talk to the DBD::CSV
database and forward the request to the DBD::CSV
module. The DBD::CSV
module has Perl functions in it that tell it how to parse SQL and how to
hunt around in the text files to find the information you asked for. It
then returns the results to DBI
as a Perl data structure. Finally, your program gets the results from DBI
in exactly the same way that it would have if you were talking to Oracle
instead.DBI
.DBI
to talk to DBD::Oracle
, and have it use DBD::Sybase
instead. Or you might build your program to talk to a cheap, crappy
database like MS Access, and then next year when the application is doing
well and getting more use than you expected, you can upgrade to a better
database next year without changing any of your code.DBD
modules for talking to every important kind of SQL database. DBD::Oracle
will talk to Oracle, and DBD::Sybase
will talk to Sybase. DBD::ODBC
will talk to any ODBC database including Microsoft Acesss. (ODBC is a
Microsoft invention that is analogous to
DBI
itself. There is no DBD
module for talking to Access directly.) DBD::CSV
allows SQL queries on plain text files.
DBD::mysql
talks to the excellent MySQL database from TCX DataKonsultAB in Sweden.
(MySQL is a tremendous bargain: It's $200
for commercial use,
and free for noncommerical use.)DBI
Enter name> Noether 118: Emmy Noether Enter name> Smith 3: Mark Smith 28: Jeff Smith Enter name> Snonkopus No names matched `Snonkopus'. Enter name> ^DHere is the code:
use DBI; my $dbh = DBI->connect('DBI:Oracle:payroll') or die "Couldn't connect to database: " . DBI->errstr; my $sth = $dbh->prepare('SELECT * FROM people WHERE lastname = ?') or die "Couldn't prepare statement: " . $dbh->errstr; print "Enter name> "; while ($lastname = <>) { # Read input from the user my @data; chomp $lastname; $sth->execute($lastname) # Execute the query or die "Couldn't execute statement: " . $sth->errstr; # Read the matching records and print them out while (@data = $sth->fetchrow_array()) { my $firstname = $data[1]; my $id = $data[2]; print "\t$id: $firstname $lastname\n"; } if ($sth->rows == 0) { print "No names matched `$lastname'.\n\n"; } $sth->finish; print "\n"; print "Enter name> "; } $dbh->disconnect;
use DBI;This loads in the
DBI
module. Notice that we don't have to load in any DBD
module. DBI
will do that for us when it needs to.my $dbh = DBI->connect('DBI:Oracle:payroll'); or die "Couldn't connect to database: " . DBI->errstr;The
connect
call tries to connect to a database. The first argument, DBI:Oracle:payroll
, tells DBI
what kind of database it is connecting to. The Oracle
part tells it to load DBD::Oracle
and to use that to communicate with the database. If we had to switch to
Sybase next week, this is the one line of the program that we would change.
We would have to change Oracle
to Sybase
.payroll
is the name of the database we will be searching. If we were going to
supply a username and password to the database, we would do it in the connect
call:
my $dbh = DBI->connect('DBI:Oracle:payroll', 'username', 'password') or die "Couldn't connect to database: " . DBI->errstr;If
DBI
connects to the database, it returns a database handle object, which we store into $dbh
. This object represents the database connection. We can be connected to
many databases at once and have many such database connection objects.DBI
can't connect, it returns an undefined value. In this case, we use die
to abort the program with an error message.
DBI->errstr
returns the reason why we couldn't connect—``Bad password'' for example.
my $sth = $dbh->prepare('SELECT * FROM people WHERE lastname = ?') or die "Couldn't prepare statement: " . $dbh->errstr;The
prepare
call prepares a query to be executed by the database. The argument is any
SQL at all. On high-end databases, prepare
will send the SQL to the database server, which will compile it. If
prepare
is successful, it returns a statement handle object which represents the statement; otherwise it returns an undefined
value and we abort the program. $dbh->errstr
will return the reason for failure, which might be ``Syntax error in SQL''.
It gets this reason from the actual database, if possible.?
in the SQL will be filled in later. Most databases can handle this. For
some databases that don't understand the ?
, the DBD module will emulate it for you and will pretend that the database
understands how to fill values in later, even though it doesn't.print "Enter name> ";Here we just print a prompt for the user.
while ($lastname = <>) { # Read input from the user ... }This loop will repeat over and over again as long as the user enters a last name. If they type a blank line, it will exit. The Perl
<>
symbol means to read from the terminal or from files named on the command
line if there were any.my @data;This declares a variable to hold the data that we will get back from the database.
chomp $lastname;This trims the newline character off the end of the user's input.
$sth->execute($lastname) # Execute the query or die "Couldn't execute statement: " . $sth->errstr;
execute
executes the statement that we prepared before. The argument $lastname
is substituted into the SQL in place of the
?
that we saw earlier. execute
returns a true value if it succeeds and a false value otherwise, so we
abort if for some reason the execution fails.while (@data = $sth->fetchrow_array()) { ... }
fetchrow_array
returns one of the selected rows from the database. You get back an array
whose elements contain the data from the selected row. In this case, the
array you get back has six elements. The first element is the person's
last name; the second element is the first name; the third element is the
ID, and then the other elements are the postal code, age, and sex.fetchrow_array
, we get back a different record from the database. When there are no more
matching records,
fetchrow_array
returns the empty list and the while
loop exits.
my $firstname = $data[1]; my $id = $data[2];These lines extract the first name and the ID number from the record data.
print "\t$id: $firstname $lastname\n";This prints out the result.
if ($sth->rows == 0) { print "No names matched `$lastname'.\n\n"; }The
rows
method returns the number of rows of the
database that were selected. If no rows were selected, then there is
nobody in the database with the last name that the user is looking
for. In that case, we print out a message. We have to do this
after the while
loop that fetches whatever rows
were available, because with some databases you don't know how many
rows there were until after you've gotten them all.
$sth->finish; print "\n"; print "Enter name> ";Once we're done reporting about the result of the query, we print another prompt so that the user can enter another name.
finish
tells the database that we have finished retrieving
all the data for this query and allows it to reinitialize the handle so
that we can execute it again for the next query.
$dbh->disconnect;When the user has finished querying the database, they type a blank line and the main
while
loop exits. disconnect
closes the connection to the database.
sub age_by_id { # Arguments: database handle, person ID number my ($dbh, $id) = @_; my $sth = $dbh->prepare('SELECT age FROM people WHERE id = ?') or die "Couldn't prepare statement: " . $dbh->errstr;
$sth->execute($id) or die "Couldn't execute statement: " . $sth->errstr;
my ($age) = $sth->fetchrow_array(); return $age; }It prepares the query, executes it, and retrieves the result.
{ my $sth; sub age_by_id { # Arguments: database handle, person ID number my ($dbh, $id) = @_;
if (! defined $sth) { $sth = $dbh->prepare('SELECT age FROM people WHERE id = ?') or die "Couldn't prepare statement: " . $dbh->errstr; }
$sth->execute($id) or die "Couldn't execute statement: " . $sth->errstr;
my ($age) = $sth->fetchrow_array(); return $age; } }There are two big changes to this function from the previous version. First, the
$sth
variable has moved outside of the function; this tells Perl that its value
should persist even after the function returns. Next time the function is
called, $sth
will have the same value as before.prepare
code is in a conditional block. It's only executed if $sth
does not yet have a value. The first time the function is called, the prepare
code is executed and the statement handle is stored into $sth
. This value persists after the function returns, and the next time the
function is called, $sth
still contains the statement handle and the prepare
code is skipped.sub age_by_id { # Arguments: database handle, person ID number my ($dbh, $id) = @_; my $sth = $dbh->prepare_cached('SELECT age FROM people WHERE id = ?') or die "Couldn't prepare statement: " . $dbh->errstr;
$sth->execute($id) or die "Couldn't execute statement: " . $sth->errstr;
my ($age) = $sth->fetchrow_array(); return $age; }Here the only change to to replace
prepare
with prepare_cached
. The prepare_cached
call is just like prepare
, except that it looks to see if the query is the same as last time. If so,
it gives you the statement handle that it gave you before.COMMIT
, and all the changes are made simultaneously. Alternatively, you can issue
the query ROLLBACK
, in which case all the queries are thrown away.employees
that looks like this:
FIRSTNAME LASTNAME DEPARTMENT_ID Gauss Karl 17 Smith Mark 19 Noether Emmy 17 Smith Jeff 666 Hamilton William 17and a table called
departments
that looks like this:
ID NAME NUM_MEMBERS 17 Mathematics 3 666 Legal 1 19 Grounds Crew 1The mathematics department is department #17 and has three members: Karl Gauss, Emmy Noether, and William Hamilton.
sub new_employee { # Arguments: database handle; first and last names of new employee; # department ID number for new employee's work assignment my ($dbh, $first, $last, $department) = @_; my ($insert_handle, $update_handle);
my $insert_handle = $dbh->prepare_cached('INSERT INTO employees VALUES (?,?,?)'); my $update_handle = $dbh->prepare_cached('UPDATE departments SET num_members = num_members + 1 WHERE id = ?');
die "Couldn't prepare queries; aborting" unless defined $insert_handle && defined $update_handle;
$insert_handle->execute($first, $last, $department) or return 0; $update_handle->execute($department) or return 0; return 1; # Success }We create two handles, one for an
insert
query that will insert the new employee's name and department number into
the employees
table, and an update
query that will increment the number of members in the new employee's
department in the department
table. Then we execute the two queries with the appropriate arguments.
employees
table, and that means that the count in the departments
table is wrong. The database now has corrupted data in it.
commit
. The version of our program with commit
looks like this:
sub new_employee { # Arguments: database handle; first and last names of new employee; # department ID number for new employee's work assignment my ($dbh, $first, $last, $department) = @_; my ($insert_handle, $update_handle);
my $insert_handle = $dbh->prepare_cached('INSERT INTO employees VALUES (?,?,?)'); my $update_handle = $dbh->prepare_cached('UPDATE departments SET num_members = num_members + 1 WHERE id = ?');
die "Couldn't prepare queries; aborting" unless defined $insert_handle && defined $update_handle;
my $success = 1; $success &&= $insert_handle->execute($first, $last, $department); $success &&= $update_handle->execute($department);
my $result = ($success ? $dbh->commit : $dbh->rollback); unless ($result) { die "Couldn't finish transaction: " . $dbh->errstr } return $success; }We perform both queries, and record in
$success
whether they both succeeded. $success
will be true if both queries succeeded, false otherwise. If the queries
succeded, we commit the transaction; otherwise, we roll it back, cancelling
all our changes.commit
, and the changes are committed automatically, which means that any other
program looking at the database either sees all of them or none.do
UPDATE
, INSERT
, or DELETE
there is no data that comes back from the database, so there is a short
cut. You can say
$dbh->do('DELETE FROM people WHERE age > 65');for example, and
DBI
will prepare the statement, execute it, and finish it. do
returns a true value if it succeeded, and a false value if it failed.
Actually, if it succeeds it returns the number of affected rows. In the
example it would return the number of rows that were actually deleted. (DBI
plays a magic trick so that the value it turns is true even when it is 0.
This is bizarre, because 0 is usually false in Perl. But it's convenient
because you can use it either as a number or as a true-or-false success
code, and it works both ways.)commit
s. When you make the connect
call, you can specify an AutoCommit
option which will perform an automatic commit
operation after every successful query. Here's what it looks like:
my $dbh = DBI->connect('DBI:Oracle:payroll', {AutoCommit => 1}, ) or die "Couldn't connect to database: " . DBI->errstr;
connect
call, you can specify a RaiseErrors
option that handles errors for you automatically. When an error occurs, DBI
will abort your program instead of returning a failure code. If all you
want is to abort the program on an error, this can be convenient:my $dbh = DBI->connect('DBI:Oracle:payroll', {RaiseError => 1}, ) or die "Couldn't connect to database: " . DBI->errstr;
while ($lastname = <>) { my $sth = $dbh->prepare("SELECT * FROM people WHERE lastname = '$lastname'"); $sth->execute(); # and so on ... }Here we interpolated the value of
$lastname
directly into the SQL in the prepare
call.
prepare
calls can take a long time. The database server has to compile the SQL and
figure out how it is going to run the query. If you have many similar
queries, that is a waste of time.$lastname
contains a name like O'Malley or D'Amico or some other name with an '
. The '
has a special meaning in SQL, and the database will not understand when you
ask it to prepare a statement that looks like
SELECT * FROM people WHERE lastname = 'O'Malley'It will see that you have three
'
s and complain that you
don't have a fourth matching '
somewhere else.$input
:x' or lastname = lastname or lastname = 'yNow our query has become something very surprising:
SELECT * FROM people WHERE lastname = 'x' or lastname = lastname or lastname = 'y'The part of this query that our sneaky user is interested in is the second
or
clause. This clause selects all the records
for which lastname
is equal to lastname
;
that is, all of them. We thought that the user was only going to be
able to see a few records at a time, and now they've found a way to
get them all at once. This probably wasn't what we wanted.References |
• A complete list of DBD modules are available here
• You can download these modules here • DBI modules are available here• You can get MySQL from www.tcx.se |
?
into the query, like this
SELECT * FROM people WHERE lastname = ?All my examples look like this. It is safer and more convenient and more efficient to do it this way.
abs | absolute value |
---|---|
chdir | change current directory |
chmod | change permissions of file/directory |
chomp | remove terminal newline from string variable |
chop | remove last character from string variable |
chown | change ownership of file/directory |
close | close a file handle |
closedir | close a directory handle |
cos | cosine |
defined | test whether variable is defined |
delete | delete a key from a hash |
die | exit with an error message |
each | iterate through keys & values of a hash |
eof | test a filehandle for end of file |
eval | evaluate a string as a perl expression |
exec | quit Perl and execute a system command |
exists | test that a hash key exists |
exit | exit from the Perl script |
glob | expand a directory listing using shell wildcards |
gmtime | current time in GMT |
grep | filter an array for entries that meet a criterion |
index | find location of a substring inside a larger string |
int | throw away the fractional part of a floating point number |
join | join an array together into a string |
keys | return the keys of a hash |
kill | send a signal to one or more processes |
last | exit enclosing loop |
lc | convert string to lowercase |
lcfirst | lowercase first character of string |
length | find length of string |
local | temporarily replace the value of a global variable |
localtime | return time in local timezone |
log | natural logarithm |
m// | pattern match operation |
map | perform on operation on each member of array or list |
mkdir | make a new directory |
my | create a local variable |
next | jump to the top of enclosing loop |
open | open a file for reading or writing |
opendir | open a directory for listing |
pack | pack a list into a compact binary representation |
package | create a new namespace for a module |
pop | pop the last item off the end of an array |
print to terminal or a file | |
printf | formatted print to a terminal or file |
push | push a value onto the end of an array |
q/STRING/ | generalized single-quote operation |
qq/STRING/ | generalized double-quote operation |
qx/STRING/ | generalized backtick operation |
qw/STRING/ | turn a space-delimited string of words into a list |
rand | random number generator |
read | read binary data from a file |
readdir | read the contents of a directory |
readline | read a line from a text file |
readlink | determine the target of a symbolic link |
redo | restart a loop from the top |
ref | return the type of a variable reference |
rename | rename or move a file |
require | load functions defined in a library file |
return | return a value from a user-defined subroutine |
reverse | reverse a string or list |
rewinddir | rewind a directory handle to the beginning |
rindex | find a substring in a larger string, from right to left |
rmdir | remove a directory |
s/// | pattern substitution operation |
scalar | force an expression to be treated as a scalar |
seek | reposition a filehandle to an arbitrary point in a file |
select | make a filehandle the default for output |
shift | shift a value off the beginning of an array |
sin | sine |
sleep | put the script to sleep for a while |
sort | sort an array or list by user-specified criteria |
splice | insert/delete array items |
split | split a string into pieces according to a pattern |
sprintf | formatted string creation |
sqrt | square root |
stat | get information about a file |
sub | define a subroutine |
substr | extract a substring from a string |
symlink | create a symbolic link |
system | execute an operating system command, then return to Perl |
tell | return the position of a filehandle within a file |
tie | associate a variable with a database |
time | return number of seconds since January 1, 1970 |
tr/// | replace characters in a string |
truncate | truncate a file (make it smaller) |
uc | uppercase a string |
ucfirst | uppercase first character of a string |
umask | change file creation mask |
undef | undefine (remove) a variable |
unlink | delete a file |
unpack | the reverse of pack |
untie | the reverse of tie |
unshift | move a value onto the beginning of an array |
use | import variables and functions from a library module |
values | return the values of a hash variable |
wantarray | return true in an array context |
warn | print a warning to standard error |
write | formatted report generation |
my %hash = ();
my $hash_ref = {}; # a reference to an empty hash, ref will return HASHThe great thing about this is that if before performing an actual assignment, you want to determine (using the ref operator) the type of thingy that a reference is pointing to, you can!... and you can expect it to be a HASH built-in type, because that is what the line above initializes it to be.
my $hash_ref; my $hash_ref = 0; # zero
$hash{ 'key' } = 'value'; # hash
$hash{ $key } = $value; # hash, using variablesHash reference:
$href->{ 'key' } = 'value'; # hash ref
$href->{ $key } = $value; # hash ref, using variables
%hash = ( 'key1', 'value1', 'key2', 'value2', 'key3', 'value3' );
%hash = ( key1 => 'value1', key2 => 'value2', key3 => 'value3', );
my %hash_copy = %hash; # copy a hash
my $href_copy = $href; # copy a hash ref
delete $hash{$key};Hash reference:
delete $hash_ref->{$key};
while ( my ($key, $value) = each(%hash) ) { print "$key => $value\n"; }A hash reference would be only slightly different:
while ( my ($key, $value) = each(%$hash_ref) ) { print "$key => $value\n"; }Solution
for my $key ( keys %hash ) { my $value = $hash{$key}; print "$key => $value\n"; }Example
my $file = $ARGV[0] || "-"; my %from = (); open FILE, "< $file" or die "Can't open $file : $!"; while( <FILE> ) { if (/^From: (.*)/) { $from{$1}++ } # count recurrences of sender } close FILE; for my $sender ( sort keys %from ) { print "$sender: $from{$sender}\n"; }
print "size of hash: " . keys( %hash ) . ".\n";Solution
my $i = 0; $i += scalar keys %$hash_ref; # method 1: explicit scalar context $i += keys %$hash_ref; # method 2: implicit scalar context
sub foo { my $hash_ref; $hash_ref->{ 'key1' } = 'value1'; $hash_ref->{ 'key2' } = 'value2'; $hash_ref->{ 'key3' } = 'value3'; return $hash_ref; } my $hash_ref = foo(); print "the keys... ", sort keys %$hash_ref, "...\n";
$requiredPatches_href->{ $patch }->{ os } = $os; $requiredPatches_href->{ $patch }->{ arch } = $arch; $requiredPatches_href->{ $patch }->{ info } = $info;Solution
$requiredPatches_href->{ $patch } = { os => $os, arch => $arch, info => $info, };
sub foo { my ( $login, $p, $uid, $gid, $gecos, $dir, $s ); my %HoH = (); my $file = '/etc/passwd'; open( PASSWD, "< $file" ) or die "Can't open $file : $!"; while( <PASSWD> ) { ( $login, $p, $uid, $gid, $gecos, $dir, $s ) = split( ':' ); $HoH{ $login }{ 'uid' } = $uid; $HoH{ $login }{ 'gid' } = $gid; $HoH{ $login }{ 'dir' } = $dir; } close PASSWD; return \%HoH; }
my $rHoH = foo(); my( $uid, $gid, $dir ); for my $login ( keys %$rHoH ) { $uid = $rHoH->{ $login }->{ 'uid' }; # method 1 most readable $gid = ${ $rHoH->{ $login } }{ 'gid' }; # method 2 $dir = ${ ${ $rHoH }{ $login } }{ 'dir' }; # method 3 least readable print "uid: $uid, gid: $gid, dir, $dir.\n"; }Solution
my $rHoH = foo(); for my $k1 ( sort keys %$rHoH ) { print "k1: $k1\n"; for my $k2 ( keys %{$rHoH->{ $k1 }} ) { print "k2: $k2 $rHoH->{ $k1 }{ $k2 }\n"; } }
sub foo { my %HoHoH = (); while( ... ) { if( /LOCATION:/ ) { ... } elsif( /MODULE:/ ) { $HoHoH{ $loc }{ $module_type }{ MODULE_NAME } = $module_name; } elsif( $ARGS_ALLOWED ) { $HoHoH{ $loc }{ $module_type }{ $arg_name } = $arg_value; } } return \%HoHoH; }
my $rHoHoH = foo(); for my $k1 ( sort keys %$rHoHoH ) { print "$k1\n"; for my $k2 ( sort keys %{$rHoHoH->{ $k1 }} ) { print "\t$k2\n"; for my $k3 ( sort keys %{$rHoHoH->{ $k1 }->{ $k2 }} ) { print "\t\t$k3 => $rHoHoH->{ $k1 }->{ $k2 }->{ $k3 }\n"; } } }
while( my ($k, $v) = each %$hash_ref ) { print "key: $k, value: $v.\n"; }
print "Value EXISTS, but may be undefined.\n" if exists $hash{ $key }; print "Value is DEFINED, but may be false.\n" if defined $hash{ $key }; print "Value is TRUE at hash key $key.\n" if $hash{ $key };Example
sql_fetch_hashref()
takes care of connecting to the database, preparing the
statement, executing it, and returning the resulting row as a hash reference
using DBI's fetchrow_hashref()
method.my $answers = 'a,b,c,d,e'; my $sql = "select max_time, $answers from questions " . 'where question_number=?'; my $hash_ref = sql_fetch_hashref( $sql, $q ); my @answers = split ',', $answers; my $max_time = $hash_ref->{max_time} || '60'; my $hash_ref_ans; for my $letter ( @answers ) { $hash_ref_ans->{ $letter } = $hash_ref->{ $letter } if defined $hash_ref->{ $letter }; }The for loop made a new hash of only defined key/value pairs.
\
operator.my $sref = \$scalar; my $aref = \@array; my $href = \%hash; my $cref = \&subroutine;The thing the reference point to is the "referent".
my $other_scalar = ${$sref}; my @other_array = @{$aref}; my %other_hash = %{$href}; &{$cref} # Call the referent.
->
operator.my $stooge = $aref->[1]; my $stooge = $href->{Curly};
ref
isa
ref
without a good reasonisa
is part of the UNIVERSAL package, so you can call it on objects
my $mech = WWW::Mechanize->new; print "ok\n" if $mech->isa('LWP::UserAgent');
my $casefix = sub { return ucfirst lc $_[0] }; my $color = $casefix->("rED"); print "Color: $color\n"; # prints Red
shift
@_
array.
The shift
without an argument defaults to @_
.sub volume { my $height = shift; my $width = shift; my $depth = shift; return $height * $width * $depth; }
sub volume { my ($height, $width, $depth) = @_; return $height * $width * $depth; }
@_
@_
array.sub volume { return $_[0] * $_[1] * $_[2]; }
my $foo = 3; print incr1($foo) . "\n"; # prints 4 print "$foo\n"; # prints 3 sub incr1 { return $_[0]+1; }This can be good if you want it to be:
sub incr2 { return ++$_[0]; }
sub square { my $number = shift; return $number * $number; } my $n = square( 'Dog food', 14.5, 'Blah blah blah' );Only the first argument is used by the function. For that matter, you can call the function with any number of arguments, even no arguments:
my $n = square();and Perl won't complain.
sub square($) { ... } my $n = square( 1, 2, 3 ); # run-time errorHowever, don't use them. They don't work on objects, and they require that the subroutines be declared before they're called. They're a nice idea, but just not practical.
BEGIN
blockBEGIN
is a special type of code block. It allows
programmers to execute code during Perl's compile phase, allowing for
initializations and other things to happen.BEGIN
any time you use
a module; the following two statements are equivalent:use WWW::Mechanize; BEGIN { require WWW::Mechanize; import WWW::Mechanize; }
my @stooges = qw( Moe Larry Curly ); my @sandwiches = qw( tuna ham-n-cheese PBJ ); lunch( @stooges, @sandwiches );Then what's passed in to
lunch
is the list( "Moe", "Larry", "Curly", "tuna", "ham-n-cheese", "PBJ" );Inside
lunch
, how can you tell where the stooges end and the sandwiches begin? You can't. If you try this:sub lunch { my (@stooges, @sandwiches) = @_;then all six elements go into
@stooges
and @sandwiches
gets nothing.lunch( \@stooges, \@sandwiches ); sub lunch { my $stoogeref = shift; my $sandwichref = shift; my @stooges = @{$stoogeref}; my @sandwichref = @{$sandwichref}; ... }