Perl Object-Oriented Programming
There are two different implementations of object-oriented programming in Perl:
One is based on anonymous hash tables, where each object instance is essentially a reference to an anonymous hash table. In this anonymous hash table, all instance attributes are stored.
The other is based on arrays. When defining a class, we create an array for each instance attribute, and each object instance is essentially a reference to an index in these arrays. In these arrays, all instance attributes are stored.
Basic Object-Oriented Concepts
Object-oriented programming has many basic concepts, and here we focus on three: object, class, and method.
Object: An object is a reference to data items in a class.
Class: A class is a Perl package that contains methods for the object.
Method: A method is a Perl subroutine, and the class name is its first parameter.
Perl provides the bless()
function, which is used to construct objects. By associating a reference with the class name using bless
, the reference is returned to construct an object.
Class Definition
A class is simply a package.
A package can be used as a class, and functions within the package can be used as methods of the class.
Perl packages provide independent namespaces, so method and variable names in different packages do not conflict.
The file suffix for Perl classes is .pm
.
Next, we create a Person
class:
package Person;
The scope of the class code extends to the end of the script file or until the next package
keyword.
Creating and Using Objects
To create an instance (object) of a class, we need to define a constructor function. Most programs use the class name as the constructor function, but Perl allows any name.
You can use various Perl variables as Perl objects. Most of the time, we use array or hash references.
Next, we create a constructor function for the Person
class using Perl's hash reference.
When creating an object, you need to provide a constructor, which is a subroutine that returns a reference to the object.
Here is an example:
package Person;
sub new
{
my $class = shift;
my $self = {
_firstName => shift,
_lastName => shift,
_ssn => shift,
};
# Print user information
print "First Name: $self->{_firstName}\n";
print "Last Name: $self->{_lastName}\n";
print "SSN: $self->{_ssn}\n";
bless $self, $class;
return $self;
}
Next, we create an object:
$object = new Person("Xiao Ming", "Wang", 23234345);
Defining Methods
Methods in Perl classes are just Perl subroutines, also known as member functions.
The definition of methods in Perl object-oriented programming does not provide any special syntax, but it is stipulated that the first parameter of a method is either an object or a referenced package.
Perl does not provide private variables, but we can manage object data through auxiliary means.
Next, we define a method to get the first name:
sub getFirstName {
return $self->{_firstName};
}
Similarly, it can also be written as:
sub setFirstName {
my ( $self, $firstName ) = @_;
$self->{_firstName} = $firstName if defined($firstName);
return $self->{_firstName};
}
Next, we modify the code in the Person.pm
file as follows:
#!/usr/bin/perl
package Person;
sub new
{
my $class = shift;
my $self = {
_firstName => shift,
_lastName => shift,
_ssn => shift,
};
# Print user information
print "First Name: $self->{_firstName}\n";
print "Last Name: $self->{_lastName}\n";
print "SSN: $self->{_ssn}\n";
bless $self, $class;
return $self;
}
sub setFirstName {
my ( $self, $firstName ) = @_;
$self->{_firstName} = $firstName if defined($firstName);
return $self->{_firstName};
}
return $self->{_firstName};
}
sub getFirstName {
my( $self ) = @_;
return $self->{_firstName};
}
1;
employee.pl script code is as follows:
Example
#!/usr/bin/perl
use Person;
$object = new Person("Xiao Ming", "Wang", 23234345);
# Get name
$firstName = $object->getFirstName();
print "Name before setting: $firstName\n";
# Use helper function to set name
$object->setFirstName("Xiao Qiang");
# Get name via helper function
$firstName = $object->getFirstName();
print "Name after setting: $firstName\n";
After executing the above program, the output is:
$ perl employee.pl
First Name: Xiao Ming
Last Name: Wang
ID: 23234345
Name before setting: Xiao Ming
Name after setting: Xiao Qiang
Inheritance
In Perl, class methods are inherited through the @ISA array, which contains the names of other packages (classes), and variable inheritance must be explicitly set.
Multiple inheritance means the @ISA array contains multiple class (package) names.
Through @ISA, only methods can be inherited, not data.
Next, we create an Employee class that inherits from the Person class.
The Employee.pm file code is as follows:
Example
#!/usr/bin/perl
package Employee;
use Person;
use strict;
our @ISA = qw(Person); # Inherit from Person
Now the Employee class includes all methods and properties of the Person class. We input the following code in the main.pl file and execute it:
Example
#!/usr/bin/perl
use Employee;
$object = new Employee("Xiao Ming", "Wang", 23234345);
# Get name
$firstName = $object->getFirstName();
print "Name before setting: $firstName\n";
# Use helper function to set name
$object->setFirstName("Xiao Qiang");
# Get name via helper function
$firstName = $object->getFirstName();
print "Name after setting: $firstName\n";
After executing the above program, the output is:
$ perl main.pl
First Name: Xiao Ming
Last Name: Wang
ID: 23234345
Name before setting: Xiao Ming
Name after setting: Xiao Qiang
Method Overriding
In the above example, the Employee class inherits from the Person class. However, if the methods of the Person class cannot meet the requirements, they need to be overridden.
Next, we add some new methods to the Employee class and override the methods of the Person class:
Example
#!/usr/bin/perl
package Employee;
use Person;
use strict;
our @ISA = qw(Person); # Inherit from Person
# Override constructor
sub new {
my ($class) = @_;
# Call the parent class constructor
my $self = $class->SUPER::new($_[1], $_[2], $_[3]);
# Add more attributes
$self->{_id} = undef;
$self->{_title} = undef;
bless $self, $class;
return $self;
}
# Override method
sub getFirstName {
my( $self ) = @_;
# This is a subclass function
print "This is a subclass function\n";
return $self->{_firstName};
}
# Add method
sub setLastName{
my ( $self, $lastName ) = @_;
$self->{_lastName} = $lastName if defined($lastName);
return $self->{_lastName};
}
sub getLastName {
my( $self ) = @_;
return $self->{_lastName};
}
1;
We input the following code in the main.pl file and execute it:
Example
#!/usr/bin/perl
use Employee;
$object = new Employee("Xiao Ming", "Wang", 23234345);
# Get name
$firstName = $object->getFirstName();
print "Name before setting: $firstName\n";
# Use helper function to set name
$object->setFirstName("Xiao Qiang");
# Get name via helper function
$firstName = $object->getFirstName();
print "Name after setting: $firstName\n";
After executing the above program, the output is:
$ perl main.pl
First Name: Xiao Ming
Last Name: Wang
ID: 23234345
Name before setting: Xiao Ming
Name after setting: Xiao Qiang
use Employee;
$object = new Employee("Xiao Ming", "Wang", 23234345);
# Get the name using the modified constructor
$firstName = $object->getFirstName();
print "Name before setting: $firstName\n";
# Set the name using an auxiliary function
$object->setFirstName("Xiao Qiang");
# Get the name using an auxiliary function
$firstName = $object->getFirstName();
print "Name after setting: $firstName\n";
After executing the above program, the output is:
$ perl main.pl
First Name: Xiao Ming
Last Name: Wang
ID: 23234345
This is a subclass function
Name before setting: Xiao Ming
This is a subclass function
Name after setting: Xiao Qiang
Default Loading
If the requested method cannot be found in the current class, all base classes, or the UNIVERSAL class, it will look for a method named AUTOLOAD(). If found, AUTOLOAD will be called, and the global variable $AUTOLOAD will be set to the fully qualified name of the missing method.
If this fails, Perl will declare an error and exit.
If you do not want to inherit the AUTOLOAD from the base class, simply do:
sub AUTOLOAD;
Destructor and Garbage Collection
When the last reference to an object is released, the object is automatically destructed.
If you want to perform some actions during destruction, you can define a method named "DESTROY" in your class. It will be called automatically at the appropriate time and perform additional cleanup as you wish.
package MyClass;
...
sub DESTROY
{
print "MyClass::DESTROY called\n";
}
Perl will pass the object reference as the only argument to DESTROY. Note that this reference is read-only, meaning you cannot modify it by accessing $_[0]. However, the object itself (e.g., "${$_[0]}", "@{$_[0]}", "%{$_[0]}", etc.) is still writable.
If you re-bless the object reference before the destructor returns, Perl will continue to call the DESTROY method of the class you re-blessed the object into after the destructor returns. This allows you to call the destructor of the base class or any other class you specify. It should be noted that DESTROY can also be called manually, but usually there is no need to do so.
After the current object is released, other objects contained within the current object will be released automatically.
Perl Object-Oriented Example
We can further understand the application of Perl object-oriented programming through the following example:
Example
#!/usr/bin/perl
# Simple class implementation below
package MyClass;
sub new
{
print "MyClass::new called\n";
my $type = shift; # Package name
my $self = {}; # Reference to an empty hash
return bless $self, $type;
}
sub DESTROY
{
print "MyClass::DESTROY called\n";
}
sub MyMethod
{
print "MyClass::MyMethod called!\n";
}
# Inheritance implementation
package MySubClass;
@ISA = qw( MyClass );
sub new
{
print "MySubClass::new called\n";
my $type = shift; # Package name
my $self = MyClass->new; # Reference to an empty hash
return bless $self, $type;
}
sub DESTROY
{
print "MySubClass::DESTROY called\n";
}
sub MyMethod
{
my $self = shift;
$self->SUPER::MyMethod();
print " MySubClass::MyMethod called!\n";
}
# Main program calling the above classes
package main;
print "Calling MyClass methods\n";
$myObject = MyClass->new();
$myObject->MyMethod();
print "Calling MySubClass methods\n";
$myObject2 = MySubClass->new();
$myObject2->MyMethod();
print "Creating a scoped object\n";
{
my $myObject3 = MySubClass->new();
}
# $myObject3 goes out of scope here, so MySubClass::DESTROY is called
my $myObject2 = MyClass->new();
}
# Automatically calls the destructor
print "Creating object\n";
$myObject3 = MyClass->new();
undef $myObject3;
print "Script execution ends...\n";
# Automatically executes the destructor
Executing the above program, the output is:
Calling MyClass methods
MyClass::new called
MyClass::MyMethod called!
Calling MySubClass methods
MySubClass::new called
MyClass::new called
MyClass::MyMethod called!
MySubClass::MyMethod called!
Creating a scoped object
MyClass::new called
MyClass::DESTROY called
Creating object
MyClass::new called
MyClass::DESTROY called
Script execution ends...
MyClass::DESTROY called
MySubClass::DESTROY called