Subroutines are small sections of code in your PERL script that you can call on as if they are their own mini-scripts.
For example, let's say you want to print something the same way at various parts in your script.
```perl
sub printThisWay {
print "I want it that way.";
}
```
Then all you need to do to produce that is call on that subroutine, like so...
`&printThisWay();`
Subroutines are great for when you want to compartmentalize your code, or when you have common things that you may do over and over again but they may not happen in the same order.
# Components of a Subroutine
Subroutines must be created using the `sub` function, giving it a name, and creating curly brackets to indicate all the functions you want to happen when you call the subroutine ...
```perl
sub routineName {
#your code goes here
}
```
A good example of when to use a subroutine is when you are parsing the data you've received from a user ...
```perl
sub parseData {
read(STDIN, $fromUser, $ENV{'CONTENT_LENGTH'});
$fromUser =~ s/\%20/ /g; #you may want to add even more substitutions
@pairs = split(/\&/,$fromUser);
%USERDATA = ();
for (@pairs) {
($key,$value) = split(/=/,$_);
$USERDATA{$key} = $value;
}
}
```
... and then call that subroutine at the very beginning of your code with ...
```perl
if ($ENV{'CONTENT_LENGTH'}) {
&parseData;
}
```
... which would replace the part of your code you put in the subroutine.
# Passing Information to Subroutines
You can also send information to a subroutine. Add scalar variables to the parameters of your subroutine call, and you now send information for it to work with.
As an example, let's say you want to print something, but you want to change it's color everytime it gets printed. Send the color as a parameter
```perl
&printColored("red");
```
In your subroutine, add the parameter as the first line ...
```perl
sub printColored {
$myColor = $_; #passes the single scalar variable to $myColor
print "<span style=\"color:$myColor\">My new color</span>";
}
```
You can also pass multiple variables, and receive them as a list ...
```perl
&printColored("purple","My Message");
```
```perl
sub printColored {
($myColor,$myMessage) = @_; #passes a list of scalars and renames them
print "<span style=\"color:$myColor\">$myMessage</span>";
}
```
# Using Subroutines as different branches of an algorithm
You can send your code to do different things using subroutines. All you need is a variable that will tell your code which subroutine to choose.
## Example
You have a series of forms that you want to do different things based on which button the user presses. In each form, give the button the same name, in this example we'll use `action` ...
```html
<button name="action" value="firstRoutine">Preview Email</button>
<button name="action" value="secondRoutine">Send Email</button>
```
Let's say you receive this information in a `%USERDATA` hash. Depending on which button the user clicked, it will send the code a different value for `$USERDATA{'action'}`. Now your PERL code can decide what to do based on what button they clicked ...
```perl
if ($USERDATA{'action'} eq "firstRoutine") {
&firstRoutine;
} elsif ($USERDATA{'action'} eq "secondRoutine") {
&secondRoutine;
} else {
&errorMessage("You somehow sent the wrong action message!");
}
```
Then your subroutines would look as follows;
```perl
sub firstRoutine { ... }
sub secondRoutine { ... }
sub errorMessage {
$message = $_;
print "<h1 style=\"color:red\;\">HEY! $message</h1>\n";
}
```
This allows you to potentially parse your data, then using a button's value use the exact same parsed data for every algorithm you will be using.
# Common practice
Now we're getting to a point where there are lots of things happening in your code. Formatting is now going to become a big deal. So let's discuss some common practice...
## Every PERL script needs to start with a shebang
The `#! /usr/bin/perl -w` shebang *must* be the top line.
## Then your called modules
Anything you need to `use` like `use CGI::Carp` should usually be at the top of your script file.
## Then parse your data
This may include having an option for if data is sent from an HTML form *or* from the URL Parameters (like below)
```perl
if ($ENV{'CONTENT_LENGTH'}) {
read(STDIN,$fromUser,$ENV{'CONTENT_LENGTH'});
} elsif ($ENV{'QUERY_STRING'} ne "") {
$fromUser = $ENV{'QUERY_STRING'};
}
&parseData;
#the parseData subroutine would be the same as above, minus the read command
```
## Add the Headers of your output
Tell the server what type of file the PERL script will produce, and get the basics going. You can even include this in a subroutine (like below)
```perl
&makeHeaders;
# you would make this subroutine at the bottom of your code
sub makeHeaders{
print "Content-Type: text/html\n\n";
print "<!DOCTYPE html>\n";
print "<html><head><title>Emailer</title></head></html>\n";
}
```
## Make all your conditional process calls
Following all that setup, here is where you would place your conditional calls, having the code run different subroutines based on the data you got from your user.
## Add a Footer of your output
You know that certain code *must* be at the bottom of your file, like the `</body></html>` tags, or anything else you deem important enough to always be at the bottom of your code (Mr. Windsor adds a Copyright message at the bottom of all his codes). You can put that in a subroutine, or simply print it after all your conditional process calls.
```perl
print "</body></html>";
```
## Put your subroutine definitions at the bottom
All your subroutine definitions can sit at the bottom of your file, one after another. That separates them clearly from the headers and conditional process calls. You should also comment above each subroutine to provide yourself with a reminder of what that subroutine is, and why you might call it.
# A Finished Example
```perl
#!/usr/bin/perlml
use warnings;
use diagnostics;
use CGI::Carp qw(warningsToBrowser fatalsToBrowser);
use Fcntl qw(:flock :seek);
use utf8;
use Mail::Sendmail;
# Parsing Data
if ($ENV{'CONTENT_LENGTH'}) {
read(STDIN,$fromUser,$ENV{'CONTENT_LENGTH'});
} elsif ($ENV{'QUERY_STRING'} ne "") {
$fromUser = $ENV{'QUERY_STRING'};
}
&parseData;
&makeHeaders;
if ($USERDATA{'action'} eq "firstRoutine") {
&firstRoutine;
} elsif ($USERDATA{'action'} eq "secondRoutine") {
&secondRoutine;
} else {
&errorMessage("You somehow sent the wrong action message!");
}
print "</body></html>\n";
### SUBROUTINES ###
# Parses the data received by either an HTML form or URL parameters
sub parseData {
$fromUser =~ s/\%20/ /g;
@pairs = split(/\&/,$fromUser);
%USERDATA = ();
for (@pairs) {
($key,$value) = split(/=/,$_);
$USERDATA{$key} = $value;
}
}
# Prints the top of the HTML right away
sub makeHeaders{
print "Content-Type: text/html\n\n";
print "<!DOCTYPE html>\n";
print "<html><head>\n";
print " <title>Emailer</title>\n";
print "</head><body>\n";
}
# Email Form
sub firstRoutine {
# insert your awesome code here
}
# Sends the Email
sub secondRoutine {
# insert your awesome code here
}
# Types an error message if they didn't go to either the 1st or 2nd options
sub errorMessage {
$whatsTheError = $_;
print "<h2>$whatsTheError</h2>\n";
}
```