Object-Oriented Programming

A module is a Perl package, objects in Perl are based on references to data items within a package. An object in Perl is simply a reference to something that knows which class it belongs to. As in other languages you declare a class and then create objects of that class. All objects of a particular class behave in a certain way, which is governed by the methods of that class. You can create new classes by defining new ones or by inheriting properties from an existing class.

There are three important rules

The inheritance feature in Perl is not the same as in other languages, Perl classes inherit methods (subroutines) only, you must implement your own mechanisms for data inheritance. Because each class is a package, it has its own name space with its own associative array of symbols names. Each class can therefore use its own independedt set of symbols names. You can address the variables in a class using the double colon (::) operator, members of a class are addressed as $class::$member.

Creating a Class

Remembering that a module is a Package and a Pacakge is a class the file extension for the class will be .pm, a perl module file must have a 1; to terminate the package.

Basic Package

package Cocoa;
#
#   put required statements in for all required or imported packages
#

#
#   Just add your code here
#

1;     # terminate the package with the required 1;

Blessing a Constructor

A constructor is a Perl subroutine in a class that returns a reference to something that has the class name attched to it. Connecting a class name with a reference is reffered to as blessing an object because the function to establish the connection is called bless.

Blessing an object

package Cocoa;

sub new {
   my $this = {};     # create an anonymous hash, and #self points to it
   bless this;        # Connect the hash to the package Cocoa
   return this;       # Return the reference to the hash
}

1;     # terminate the package with the required 1;

## To create a Cocoa object
push (@INC,'pwd');             # add the local directory to the search path @INC (where your package is located
use Cocoa;                     # include the Cocoa package using the @INC path/s
$cup = new Cocoa;              # Create the Cocoa object

# $cup = Cocoa->new();         # There are many ways to create a object
# $cup = Cocoa::new();

Forcing how to create an object

package Cocoa;

sub new {
   my $this = shift;                    # Get the class name (used when calling for another class)
   my $class = ref($this) || $this;     # If the class exists, use it else use the reference

   my $this = {};
   bless $this, $class;                 # Use class name to bless() reference

   $this->doInitialization();           # call a function within the object         
   return this;       
}

1;     # terminate the package with the required 1;

Note: you are now forced to create an object by using either

$cup = new Cocoa;             
$cup = Cocoa->new();        
$cup = Cocoa::new();

Instance Variables

The arguments to a new() function for a constructor are called instance variables, they are used to do initialization for each instance of an objects as it created. You can either use an anonymous array or an anonymous hash to hold instance variables.

Instance Variables ## Cocoa Package (Cocoa.pm)
package Cocoa;

sub new {
   my %parm = @_;
   my $this = {};

   $this->{'Name'} = $parm{'Name'};
   $this->{'x'} = $parm{'x'};
   $this->{'y'} = $parm{'y'};

   bless $this, $type;
}

1;

## Main Program (Test.pl)
use Cocoa;

$cup = Cocoa::new('Name' => 'top', 'x' => 10, 'y' => 20);

print "Name = $cup->{'Name'} \n";
print "x = $cup->{'x'} \n";
print "y = $cup->{'y'} \n"

Methods

A method is simply a subroutine, there is no special syntax for method definition. Perl has two types of methods:

A static method applies functionality to the entire class as a whole because it uses the name of the class. Constructors are static methods

A virtual method first shifts the first argument into a self or this variable and then use that shifted value as an ordinary reference.

Inheritance in Perl is through the @ISA array, this array contains the names of the classes (packages) to look for methods in other classes in if a method in the current package is not found.

Example
## Package (Cocoa.pm)
package Cocoa; require Exporter; @ISA = qw(Exporter);                                 # set the @ISA array with the name of the Exporter class
# to look for
@EXPORT = qw(setImports, declareMain, closeMain);    # Export the methods in to the export array # This routine creates the references for imports in Java functions sub setImports{ my $class = shift @_; my @names = @_; foreach (@names) { print "import " . $_ . ";\n"; } } # This routine declares the main function in a Java script sub declareMain { my $class = shift @_; my ( $name, $extends, $implements) = @_; print "\n public class $name"; if ($extends) { print " extends " . $extends; } if ($implements) { print " implements " . $implements; } print " { \n"; } # # This routine declares the main function in a Java script # sub closeMain { print "} \n"; } # This subroutine creates the header for the file. sub new { my $this = {}; bless $this; return $this; } 1; ## Main Program (Test.pl)
use Cocoa; $cup = new Cocoa; $cup->setImports( 'java.io.InputStream', 'java.net.*'); $cup->declareMain( "Msg" , "java.applet.Applet", "Runnable"); $cup->closeMain(); ## Could be rewritten as Cocoa::setImports($cup, 'java.io.InputStream', 'java.net.*'); Cocoa::declareMain($cup, "Msg" , "java.applet.Applet", "Runnable"); Cocoa::closeMain($cup);

Destructors

Perl tracks the number of links to objects, when the last reference to an object is freed to the memory poolo, the object is automatically destroyed. If you want to capture control just before the object is freed, you can define a destroy() method in your class, you can use this method to perform any clean up.

Example

sub DESTROY {

## Add your code here

}

Inheritance

Methods in classes are inheriated with the paths in the @ISA array, variables must be explicity setup for inheritance.

Example
## Package (Bean.pm)
package Bean;

require Exporter;

@ISA = qw(Exporter);
@EXPORT = qw(setBeanType);

# Constructor
sub new { my $type = shift; my $this = {}; $this->{'Bean'} = 'Colombian'; bless $this, $type; return $this; } # This subroutine sets the class name sub setBeanType{ my ($class, $name) = @_; $class->{'Bean'} = $name; print "Set bean to $name \n"; } 1; ## Package (Coffee.pm) - file to illustrate inheritance. package Coffee; require Exporter; require Bean; @ISA = qw(Exporter, Bean); @EXPORT = qw(setImports, declareMain, closeMain); # set item sub setCoffeeType { my ($class,$name) = @_; $class->{'Coffee'} = $name; print "Set coffee type to $name \n"; } # constructor sub new { my $type = shift; my $this = Bean->new(); ##### <- LOOK HERE!!! - Inheritance at work #### $this->{'Coffee'} = 'Instant'; # unless told otherwise bless $this, $type; return $this; } 1; ## Main Program (Test.pl) push (@INC,'pwd'); use Coffee; $cup = new Coffee; print "\n -------------------- Initial values ------------ \n"; print "Coffee: $cup->{'Coffee'} \n"; print "Bean: $cup->{'Bean'} \n"; print "\n -------------------- Change Bean Type ---------- \n"; $cup->setBeanType('Mixed'); print "Bean Type is now $cup->{'Bean'} \n"; print "\n ------------------ Change Coffee Type ---------- \n"; $cup->setCoffeeType('Instant'); print "Type of coffee: $cup->{'Coffee'} \n";

Overriding Methods

It is possible in Perl (as in other languages) to override methods, in order to call the inheriated method you use the SUPER:: pseudo-class reserved word. In the example below there are two toString methods one is overriden.

Overriding example
## Main Program (test.pl)
use pkgOne; $test = new pkgOne; print $test->toString(); ## Package (pkgOne.pm)
package pkgOne; require Exporter; require pkgTwo; @ISA = (Exporter, pkgTwo);                ## Inheritance path @EXPORT = qw(toString); sub new { my $class = shift; my $this = pkgTwo->new();               ## Inheritance here bless $this, $type; return $this; } sub toString {                            ## overriding pkgTwo toString method    my $this = shift;
   printf("This is pkgOne toString\n");
   print $this->SUPER::toString() . "\n";  ## A call to super class pkgTwo method toString } 1; ## Package (pkgTwo.pm)
package pkgTwo; require Exporter; @ISA = (Exporter); @EXPORT = qw(toString); sub new { my $type = shift; my $this = {}; bless $this, $type; return $this; } sub toString { print "pkgTwo toString being called by SUPER::\n"; } 1;

Miscellaneous Features of Perl

There are a number of miscellaneous features that Perl has that have not fallen into the previous categories which i will touch on now.

Require Function

This function provides away to break your program into separate files and create libraries of functions. When the Perl interpreter sees the require statement it searchs the directories specified by the built-in array variable @INC for the file specified. The file is executed if found, if not found then the program aborts and displays a error message.

Require Function

require ("myprog.pl");          ## executes the myprog.pl program

@proglist = ("test_prog1.pl", "test_prog2.pl", "test_prog3.pl");
require ($proglist[0]);
require ($proglist[1]);
require ($proglist[2]);

require;                        ## the value of $_ is the file name whose contents are to be executed

Most of the time however you will use the require function to pull in subroutines from Perl programs that can be used. You can create specific libraries for Databases, Network, Security.

Using subroutines from other Perl programs ## Main Program (test.pl)
require ("function.pl");                ## execute the function.pl program

toString();                             ## The toString subroutine obtained from function.pl

## Function program (functions.pl)
print "Library: functions";

sub toString {
   print "A subroutine in the function library ";
}

The last thing require can do is to make sure that you use a specific version of Perl, maybe the program contains syntax that can only be run in version 5.6.

Specify a Perl version

require 5.001;                          ## your program requires version 5.001 or above to run

Note: if you run this on a older version of perl it will terminate with an error

$#<array> Variable

For each variable defined in your program, a variable named $#<array>, in which array is the name of your array is also defined. This variable contains the subscript of the last element of the array.

$#array example my @myarray = qw( 1 2 3 4);

$last_subscript = $#myarray;

print "Last element in myarray is: " . $last_subscript . "\n";

Note: $[ can affect $#array as $[ determines the first subscript number (by default a 0) - see perl cheat sheet for more information on $[

You commonly see this variable being used in the $#ARGV to determine the number of variables passed to a perl program.

Commandline arguments if ( $#ARGV == -1 ) {                                 ## -1 means no elements
   die ("No file parameters have been passed");
}           

You can create very large arrays using the $#<array>, or shorten an array

Create very large array

$#veryBigArray = 9999;                                ## create an array with 10,000 elements

Note: if it cannot create the array the program terminates

Shorten an array $#varyBigArray = 5000;                                ## destroy elements from 5001 to 10,000

Alternative String Delimiters

You can use single or double quotes for strings, double quotes will search and replace variable names. There are a number of other delimiters choices you can use

Alternative String Delimiters $test_string = "World";

$string1 = 'Hello $test_string';
$string2 = "Hello $test_string";

$string3 = q'Hello $test_string';               ## same as using single quotes
$string4 = qq/Hello $test_string/;              ## same as using double quotes

print $string1 . "\n";
print $string2 . "\n";
print $string3 . "\n";
print $string4 . "\n";

Break string into words @myarray = qw(hello there it's a nice day);

Defining Strings Using <<

You can use << to indicate the beginning of a string, this is also known as a here document.

<< example

$longstring = <<END;                             ## defining a terminatation string (END) - note the semicolon
The first part a a very very very long string
The second part a a very very very long string
The third part a a very very very long string
END                                               ## used to terminate the here doc

You can also use to automatic input information in other programs such as FTP, Telnet

FTP example usr/bin/ftp<<END;                      ## END is the terminating string
open ftp.datadisk.co.uk                ## FTP commands
user pvalle
password
cd public/upload
put $file
bye
END                                    ## here doc finish

Special Internal Values

You can use three special values in your program

Example print "Line number is: " . __LINE__ . "\n";
print "Program is: " . __FILE__ . "\n\n";

## Use data in the file
while (<DATA>) {
   print;
}

__END__                       ## you could have used __DATA__ means the same
hello
first data line
2nd data line

Back Quotes to Invoke System commands

You can run system commands using back quotes, the output of the command will be treated as string.

Example

$myname = `whoami`;               ## Unix system command
            
$ip_info = `ipconfig`;            ## Windows system command
print "Return code: " . $?;       ## The return code of the execute system command

print $myname ;
print $ip_info;

 

Note: the return code of the system command is store in system variable $?

Perl Debugger

There are occasions were you have a bug in your code and you just cannot find it, rather than litter your code with debug print statements sometimes it is better to use the Perl debugger, which can walkthrough your code and examine variables.

Entering and Quiting the Debugger

To debug a Perl program you specify the -d option when you run the program.

Entering the debugger

# perl -d <perl_program>

## Running test.pl
C:\perl>perl -d test.pl

Loading DB routines from perl5db.pl version 1.3
Editor support available.

Enter h or `h h' for help, or `perldoc perldebug' for more help.

main::(test.pl:1): print "hello world\n";

DB<1>

 

Quiting the debugger DB<1> q

Debugger Help

There are lots of option that the debugger uses, just use the help page to give you an idea of whats available.

Debugger help
C:\perl>perl -d test.pl

Loading DB routines from perl5db.pl version 1.3
Editor support available.

Enter h or `h h' for help, or `perldoc perldebug' for more help.

main::(test.pl:1):      print "hello world\n";

  DB<1> h
List/search source lines:               Control script execution:
  l [ln|sub]  List source code            T           Stack trace
  - or .      List previous/current line  s [expr]    Single step [in expr]
  v [line]    View around line            n [expr]    Next, steps over subs
  f filename  View source in file           Repeat last n or s
  /pattern/ ?patt?   Search forw/backw    r           Return from subroutine
  M           Show module versions        c [ln|sub]  Continue until position
Debugger controls:                        L           List break/watch/actions
  o [...]     Set debugger options        t [expr]    Toggle trace [trace expr]
  <[<]|{[{]|>[>] [cmd] Do pre/post-prompt b [ln|event|sub] [cnd] Set breakpoint
  ! [N|pat]   Redo a previous command     B ln|*      Delete a/all breakpoints
  H [-num]    Display last num commands   a [ln] cmd  Do cmd before line
  = [a val]   Define/list an alias        A ln|*      Delete a/all actions
  h [db_cmd]  Get help on command         w expr      Add a watch expression
  h h         Complete help page          W expr|*    Delete a/all watch exprs
  |[|]db_cmd  Send output to pager        ![!] syscmd Run cmd in a subprocess
  q or ^D     Quit                        R           Attempt a restart
Data Examination:     expr     Execute perl code, also see: s,n,t expr
  x|m expr       Evals expr in list context, dumps the result or lists methods.
  p expr         Print expression (uses script's current package).
  S [[!]pat]     List subroutine names [not] matching pattern
  V [Pk [Vars]]  List Variables in Package.  Vars can be ~pattern or !pattern.
  X [Vars]       Same as "V current_package [Vars]".  i class inheritance tree.
  y [n [Vars]]   List lexicals in higher scope .  Vars same as V.
  e     Display thread id     E Display all thread ids.
For more help, type h cmd_letter, or run perldoc perldebug for all docs.

  DB<1>

Debugger Commands

List your program l
Display lines immediately preceding the last displayed line -
List a window of lines specifing a line number w 7
Search for patterns //   (search forward)
??   (search backward)
List subroutines S    (upper case)
Execute a single statement s    (lower case)
Execute one statement then display next line of code n
Execute the reminder of the program f
Repeat the last s or n command <enter>
Finish executing the reminder of a subroutine r
Display all the located variables in the current package X
Display all the located variables in the all the packages V
Set a breakpoint (you can create as many as you wish) b 10                     (break @ line number)
b toString               (break @ subroutine)
b 10 ($curdir eq "")     (break @ 10 if $curdir is empty)
Execute program until breakpoint c                 (use set breakpoint)
c 12              (use a temporary line number breakpoint)
List all your breakpoints or actions L
Delete breakpoints d 10              (delete breakpoint 10)
D                 (delete all breakpoints)
Turn on trace mode t                 (toggle on and off)
Execute an action (you can create as many as you wish) a 10 print ("curdir is $curdir\n");
To delete all created actions A
Execute a command before or after going further > print ("curdir is $curdir\n");    (before)
< print ("curdir is $curdir\n");    (after)
Using new statements in the bugger @array = (1,2,3);
History command H
Execute previous command (use history to get commands run) !
!5            (execute command 5)
Display stack trace T
Print an expression p $curdir + 1
Define your own aliases pc print (curdir is $curdir\n");
pc