Perl is by far the current language of choice for writing Common Gateway Interface (CGI) programs. Among the reasons for choosing Perl is its availability, its ease of use and its robustness. With Perl 5, object-oriented programming (OOP) has been added to this list.
This article briefly discusses how you can write object-oriented CGI scripts using Perl. The article introduces some of Perl’s object-oriented concepts and syntax. The article also discusses Lincoln Stein’s CGI class which you can use off-the-shelf to rapidly develop robust CGI scripts. The article concludes by extending Mr. Stein’s CGI class to develop a small template engine used in processing a multi-page form.
To take full advantage of the information presented here, you should have some familiarity with Perl 5 and especially with Perl references. If constructors, polymorphism and inheritance are old hat to you, then read on. If not, you will most likely find the following discussion rather confusing and obtuse. But fear not, you still may find some value in learning about the CGI package that is discussed below.
Object-oriented programming in Perl
Perl 5 introduced OOP to Perl. It also introduced references, without which there wouldn’t be much OOP in Perl, so we start at the beginning.
References
A reference in Perl is like a pointer in C or a reference in Java: it refers to something. In Perl, you can have a reference to a scalar value, an associative array, a list, a subroutine, etc. (imagine pointers to these things).
So how do you create a reference? Quite simply, by using the backslash operator. For instance:
$scalarref = $scalar;
$arrayref = @array;
$hashref = %hash;
These all create references to existing things. What about creating a new reference? You do this by creating an anonymous reference, for instance:
$hashref = {};
$arrayref = [];
As is generally the case with Perl, there is more than one way to create a reference, but this should give you the idea (you can find more information at the Perl site).
Having created these references, how do you dereference them? You can either “double dereference” the reference, for instance $$hashref{‘key’}, or you can use the handy-dandy -> operator borrowed from C, $hashref->{‘key’}. Which you choose is up to you.
Classes, objects, and methods
If you’ve programmed in Perl a lot, you’ve probably run into Perl packages or modules. Like Java packages, a Perl package is nothing more than a namespace that can be used to “encapsulate” related data and functions. It should not be very surprising then, that classes are nothing more than packages that define some set of methods that act on the class’ members.
Along these lines, an object is nothing more than a reference that knows the class to which it belongs. A method is nothing more than a subroutine that expects an object reference as its first argument. Keep these definitions in mind as you read through the code below. Given these tidbits, let’s create a simple Person class. Each Person has a first name and a last name. We create the class as a Perl package in a file called Person.pm (all Perl packages have the .pm extension). We also have a small script to test the class.
Listing One — Person.pm
package Person;
$VERSION = 1.0;
##
## This had better be called with two parameters!
## SYNTAX: new Person (“George”, “Washington”);
##
sub new {
my ($class, @params) = @_;
# create an anonymous hash to hold our instance variables
# this becomes our object once it is “blessed”
my($this) = {};
# place any initialized parameters
if ($#params >= 1) {
$this->{‘FIRST_NAME’} = $params[0];
$this->{‘LAST_NAME’} = $params[1];
} else {
$this->{‘FIRST_NAME’} = undef;
$this->{‘SECOND_NAME’} = undef;
}
# bless us as belonging to the Person class
bless ($this, $class);
return $this;
}
##
## Returns a string of the first and last name concatenated together
##
sub getName {
# shift the argument stack to get a reference to the invoking object
my ($this) = shift;
return “$this->{‘FIRST_NAME’} $this->{‘LAST_NAME’}”;
}
Listing Two — Test.pl
#!/usr/local/bin/perl
use Person;
$thePresident = new Person(“Bill”, “Clinton”);
print $thePresident ->getName(), “n”;
The Person package defines two methods, new() and getName(). new() acts as the constructor for the Person object. Note, however, that “new” is not a keyword in the Perl language. You could just as easily called the constructor foo() and invoked it as foo Person(“Bill”, “Clinton”). Again, you can just as easily invoke it as Person->new(“Bill”, “Clinton”).
So far, nothing special is going on here. Basically, the constructor is a method that expects the name of a class to be the first parameter. The object is represented by an anonymous hash (it could just as easily and slightly more efficiently have been represented as an array). Each instance variable is a key/value pair in the anonymous hash.
Bless you my object!
The object-oriented magic occurs with the bless statement. Blessing an object reference makes it a part of the specified class. Once blessed, the reference can be used to call its methods. When a method is invoked, the first parameter is a reference to the object on which the method is being invoked. You will notice how the Person::getName() method shifts the argument stack to get the object reference. What C++ compilers do for you automatically with the “this” pointer, you have to do by hand in Perl.Inheritance and all of that good stuff
None of this would be very exciting if the real meat of OOP weren’t included. Here we are talking about inheritance, polymorphism and all of that good stuff. The good news is that that stuff is in there. For instance, let’s say that we want to subclass Person and make an Employee class. Employee inherits from Person.Listing Three — Employee.pm
package Employee;
$VERSION = 1.0;
use Person;
# declare who we inherit from
@ISA = (“Person”);
##
## This had better be called with three parameters!
## SYNTAX: new Employee (“George”, “Washington”, 1234);
##
sub new {
my ($class, @params) = @_;
# call our superclasses constructor
$this = Person::new($class, @params);
# add our member variable
$this->{‘EMPLOYEE_ID’} = $param[2];
# bless us as an Employee
bless($this, $class);
return ($this);
}
##
## prints out an employee record
##
sub printRecord {
# shift the argument stack to get a reference to the invoking object
my ($this) = shift;
print $this->getName, “n$this->{‘EMPLOYEE_ID’}n”;
}
Listing Four — TestEmployee.pl
#!/usr/local/bin/perl
use Employee;
$empl = new Employee (“George”, “Bush”, 1234);
$empl->printRecord();
You will notice that the Employee package declares an array @ISA (read it as “is a”). @ISA defines a list of classes from which the Employee class inherits. Note, however, that the Employee class only inherits its parents’ methods, not their fields. To inherit a parent’s fields, the subclass must manually construct the parent to capture the parent’s fields and values. In the case above, you can see that Employee invokes Person::new() and then adds the EMPLOYEE_ID field to its own representation.
Dan Gildor is a consultant for inTouch Technology Corp. specializing in cross-platform intranet and extranet technologies. He can be reached at gyld@in-touch.com.