Perl 简明教程
Object Oriented Programming in PERL
我们已经学习过 Perl 中的引用以及 Perl 匿名数组和哈希。Perl 中的面向对象的概念在很大程度上基于引用、匿名数组和哈希。让我们开始学习面向对象 Perl 的基本概念。
We have already studied references in Perl and Perl anonymous arrays and hashes. Object Oriented concept in Perl is very much based on references and anonymous array and hashes. Let’s start learning basic concepts of Object Oriented Perl.
Object Basics
有三个主要术语,从 Perl 如何处理对象的角度对其进行了解释。这些术语是对象、类和方法。
There are three main terms, explained from the point of view of how Perl handles objects. The terms are object, class, and method.
-
An object within Perl is merely a reference to a data type that knows what class it belongs to. The object is stored as a reference in a scalar variable. Because a scalar only contains a reference to the object, the same scalar can hold different objects in different classes.
-
A class within Perl is a package that contains the corresponding methods required to create and manipulate objects.
-
A method within Perl is a subroutine, defined with the package. The first argument to the method is an object reference or a package name, depending on whether the method affects the current object or the class.
Perl 提供了一个 bless() 函数,用于返回一个最终成为对象的引用。
Perl provides a bless() function, which is used to return a reference which ultimately becomes an object.
Defining a Class
在 Perl 中定义一个类非常简单。一个类对应于它最简单的形式中的一个 Perl 程序包。要在 Perl 中创建一个类,我们首先构造一个程序包。
It is very simple to define a class in Perl. A class is corresponding to a Perl Package in its simplest form. To create a class in Perl, we first build a package.
程序包是一个自包含的、用户定义变量和子程序的单元,可以反复重用。
A package is a self-contained unit of user-defined variables and subroutines, which can be re-used over and over again.
Perl 程序包提供了 Perl 程序内部的一个独立命名空间,使子程序和变量保持独立,以免与其他程序包中的变量和子程序发生冲突。
Perl Packages provide a separate namespace within a Perl program which keeps subroutines and variables independent from conflicting with those in other packages.
要在 Perl 中声明一个名为 Person 的类,我们这样做 −
To declare a class named Person in Perl we do −
package Person;
程序包定义的范围扩展到文件末尾,或者直到遇到另一个程序包关键字。
The scope of the package definition extends to the end of the file, or until another package keyword is encountered.
Creating and Using Objects
若要创建类的实例(对象),我们需要一个对象构造函数。此构造函数是在程序包中定义的一个方法。大多数程序员选择将此对象构造函数方法命名为 new,但你可以在 Perl 中使用任何名称。
To create an instance of a class (an object) we need an object constructor. This constructor is a method defined within the package. Most programmers choose to name this object constructor method new, but in Perl you can use any name.
你可以将任何类型的 Perl 变量作为 Perl 中的对象使用。大多数 Perl 编程人员会选择对数组或哈希的引用。
You can use any kind of Perl variable as an object in Perl. Most Perl programmers choose either references to arrays or hashes.
让我们使用 Perl 哈希引用为 Person 类创建构造函数。在创建对象时,你需要提供一个构造函数,它是一个程序包中的子程序,用于返回一个对象引用。对象引用通过对程序包的类引用进行祝福来创建。例如 −
Let’s create our constructor for our Person class using a Perl hash reference. When creating an object, you need to supply a constructor, which is a subroutine within a package that returns an object reference. The object reference is created by blessing a reference to the package’s class. For example −
package Person;
sub new {
my $class = shift;
my $self = {
_firstName => shift,
_lastName => shift,
_ssn => shift,
};
# Print all the values just for clarification.
print "First Name is $self->{_firstName}\n";
print "Last Name is $self->{_lastName}\n";
print "SSN is $self->{_ssn}\n";
bless $self, $class;
return $self;
}
现在让我们看看如何创建一个对象。
Now Let us see how to create an Object.
$object = new Person( "Mohammad", "Saleem", 23234345);
如果你不想为任何类变量分配任何值,则可以在构造函数中使用简单的哈希。例如 −
You can use simple hash in your consturctor if you don’t want to assign any value to any class variable. For example −
package Person;
sub new {
my $class = shift;
my $self = {};
bless $self, $class;
return $self;
}
Defining Methods
其他面向对象语言有数据安全性的概念,以防止程序员直接更改对象数据,并且它们提供了访问器方法来修改对象数据。Perl 没有私有变量,但我们仍然可以使用辅助方法的概念来操作对象数据。
Other object-oriented languages have the concept of security of data to prevent a programmer from changing an object data directly and they provide accessor methods to modify object data. Perl does not have private variables but we can still use the concept of helper methods to manipulate object data.
让我们定义一个辅助方法来获取人员的姓氏 −
Lets define a helper method to get person’s first name −
sub getFirstName {
return $self->{_firstName};
}
用于设置人员姓名的另一个辅助函数 −
Another helper function to set person’s first name −
sub setFirstName {
my ( $self, $firstName ) = @_;
$self->{_firstName} = $firstName if defined($firstName);
return $self->{_firstName};
}
现在让我们来看看一个完整的例子:将 Person 包和辅助函数放入 Person.pm 文件中。
Now lets have a look into complete example: Keep Person package and helper functions into Person.pm file.
#!/usr/bin/perl
package Person;
sub new {
my $class = shift;
my $self = {
_firstName => shift,
_lastName => shift,
_ssn => shift,
};
# Print all the values just for clarification.
print "First Name is $self->{_firstName}\n";
print "Last Name is $self->{_lastName}\n";
print "SSN is $self->{_ssn}\n";
bless $self, $class;
return $self;
}
sub setFirstName {
my ( $self, $firstName ) = @_;
$self->{_firstName} = $firstName if defined($firstName);
return $self->{_firstName};
}
sub getFirstName {
my( $self ) = @_;
return $self->{_firstName};
}
1;
现在,让我们在 employee.pl 文件中使用 Person 对象,如下所示 −
Now let’s make use of Person object in employee.pl file as follows −
#!/usr/bin/perl
use Person;
$object = new Person( "Mohammad", "Saleem", 23234345);
# Get first name which is set using constructor.
$firstName = $object->getFirstName();
print "Before Setting First Name is : $firstName\n";
# Now Set first name using helper function.
$object->setFirstName( "Mohd." );
# Now get first name set by helper function.
$firstName = $object->getFirstName();
print "Before Setting First Name is : $firstName\n";
当我们执行以上程序时,它会产生以下结果 −
When we execute above program, it produces the following result −
First Name is Mohammad
Last Name is Saleem
SSN is 23234345
Before Setting First Name is : Mohammad
Before Setting First Name is : Mohd.
Inheritance
面向对象编程有一个非常好且有用的概念称为继承。继承简单来说就是,父类的属性和方法都可以被子类使用。因此,您不必一遍又一遍地编写相同的代码,您只需继承一个父类即可。
Object-oriented programming has very good and useful concept called inheritance. Inheritance simply means that properties and methods of a parent class will be available to the child classes. So you don’t have to write the same code again and again, you can just inherit a parent class.
例如,我们可以有一个继承自 Person 的 Employee 类。这称为“isa”关系,因为员工是人。Perl 有一个特殊的变量 @ISA 来帮助实现这一点。@ISA 管理(方法)继承。
For example, we can have a class Employee, which inherits from Person. This is referred to as an "isa" relationship because an employee is a person. Perl has a special variable, @ISA, to help with this. @ISA governs (method) inheritance.
下面是使用继承时需要考虑的重要事项 −
Following are the important points to be considered while using inheritance −
-
Perl searches the class of the specified object for the given method or attribute, i.e., variable.
-
Perl searches the classes defined in the object class’s @ISA array.
-
If no method is found in steps 1 or 2, then Perl uses an AUTOLOAD subroutine, if one is found in the @ISA tree.
-
If a matching method still cannot be found, then Perl searches for the method within the UNIVERSAL class (package) that comes as part of the standard Perl library.
-
If the method still has not found, then Perl gives up and raises a runtime exception.
因此,要创建一个新的 Employee 类,它将从我们的 Person 类继承方法和属性,我们只需编写以下代码:将此代码放入 Employee.pm 中。
So to create a new Employee class that will inherit methods and attributes from our Person class, we simply code as follows: Keep this code into Employee.pm.
#!/usr/bin/perl
package Employee;
use Person;
use strict;
our @ISA = qw(Person); # inherits from Person
现在,Employee 类具有从 Person 类继承的所有方法和属性,您可以按照如下方式使用它们:使用 main.pl 文件对其进行测试 −
Now Employee Class has all the methods and attributes inherited from Person class and you can use them as follows: Use main.pl file to test it −
#!/usr/bin/perl
use Employee;
$object = new Employee( "Mohammad", "Saleem", 23234345);
# Get first name which is set using constructor.
$firstName = $object->getFirstName();
print "Before Setting First Name is : $firstName\n";
# Now Set first name using helper function.
$object->setFirstName( "Mohd." );
# Now get first name set by helper function.
$firstName = $object->getFirstName();
print "After Setting First Name is : $firstName\n";
当我们执行以上程序时,它会产生以下结果 −
When we execute above program, it produces the following result −
First Name is Mohammad
Last Name is Saleem
SSN is 23234345
Before Setting First Name is : Mohammad
Before Setting First Name is : Mohd.
Method Overriding
子类 Employee 从父类 Person 继承了所有方法。但是,如果您想在子类中覆盖这些方法,则可以通过提供自己的实现来完成。您可以在子类中添加其他函数,也可以添加或修改其父类中现有方法的功能。可以按照如下方式完成操作:修改 Employee.pm 文件。
The child class Employee inherits all the methods from the parent class Person. But if you would like to override those methods in your child class then you can do it by giving your own implementation. You can add your additional functions in child class or you can add or modify the functionality of an existing methods in its parent class. It can be done as follows: modify Employee.pm file.
#!/usr/bin/perl
package Employee;
use Person;
use strict;
our @ISA = qw(Person); # inherits from Person
# Override constructor
sub new {
my ($class) = @_;
# Call the constructor of the parent class, Person.
my $self = $class->SUPER::new( $_[1], $_[2], $_[3] );
# Add few more attributes
$self->{_id} = undef;
$self->{_title} = undef;
bless $self, $class;
return $self;
}
# Override helper function
sub getFirstName {
my( $self ) = @_;
# This is child class function.
print "This is child class helper function\n";
return $self->{_firstName};
}
# Add more methods
sub setLastName{
my ( $self, $lastName ) = @_;
$self->{_lastName} = $lastName if defined($lastName);
return $self->{_lastName};
}
sub getLastName {
my( $self ) = @_;
return $self->{_lastName};
}
1;
现在,让我们再次尝试在 main.pl 文件中使用 Employee 对象并执行它。
Now let’s again try to use Employee object in our main.pl file and execute it.
#!/usr/bin/perl
use Employee;
$object = new Employee( "Mohammad", "Saleem", 23234345);
# Get first name which is set using constructor.
$firstName = $object->getFirstName();
print "Before Setting First Name is : $firstName\n";
# Now Set first name using helper function.
$object->setFirstName( "Mohd." );
# Now get first name set by helper function.
$firstName = $object->getFirstName();
print "After Setting First Name is : $firstName\n";
当我们执行以上程序时,它会产生以下结果 −
When we execute above program, it produces the following result −
First Name is Mohammad
Last Name is Saleem
SSN is 23234345
This is child class helper function
Before Setting First Name is : Mohammad
This is child class helper function
After Setting First Name is : Mohd.
Default Autoloading
Perl 提供了一项功能,您在任何其他编程语言中都找不到:默认子例程。这意味着,如果您定义了一个名为 AUTOLOAD(), 的函数,那么对未定义子例程的任何调用都将自动调用 AUTOLOAD() 函数。缺少的子例程的名称可以作为 $AUTOLOAD 在此子例程中访问。
Perl offers a feature which you would not find in any other programming languages: a default subroutine. Which means, if you define a function called AUTOLOAD(), then any calls to undefined subroutines will call AUTOLOAD() function automatically. The name of the missing subroutine is accessible within this subroutine as $AUTOLOAD.
默认自动加载功能对于错误处理非常有用。这里有一个实现 AUTOLOAD 的示例,您可以自己实现此函数。
Default autoloading functionality is very useful for error handling. Here is an example to implement AUTOLOAD, you can implement this function in your own way.
sub AUTOLOAD {
my $self = shift;
my $type = ref ($self) || croak "$self is not an object";
my $field = $AUTOLOAD;
$field =~ s/.*://;
unless (exists $self->{$field}) {
croak "$field does not exist in object/class $type";
}
if (@_) {
return $self->($name) = shift;
} else {
return $self->($name);
}
}
Destructors and Garbage Collection
如果您以前使用过面向对象编程,那么您将意识到在使用完一个对象后需要创建一个 destructor 来释放分配给该对象的内存。Perl 会在对象超出范围后自动为您执行此操作。
If you have programmed using object oriented programming before, then you will be aware of the need to create a destructor to free the memory allocated to the object when you have finished using it. Perl does this automatically for you as soon as the object goes out of scope.
如果您想实现析构函数,它应该负责关闭文件或执行一些额外的处理,那么您需要定义一个名为 DESTROY 的特殊方法。该方法将在 Perl 释放分配给它的内存之前在对象上调用。从所有其他方面来看,DESTROY 方法就像任何其他方法一样,您可以在此方法中实现所需的任何逻辑。
In case you want to implement your destructor, which should take care of closing files or doing some extra processing then you need to define a special method called DESTROY. This method will be called on the object just before Perl frees the memory allocated to it. In all other respects, the DESTROY method is just like any other method, and you can implement whatever logic you want inside this method.
析构函数方法只是一个名为 DESTROY 的成员函数(子例程),它将在以下情况下自动调用 -
A destructor method is simply a member function (subroutine) named DESTROY, which will be called automatically in following cases −
-
When the object reference’s variable goes out of scope.
-
When the object reference’s variable is undef-ed.
-
When the script terminates
-
When the perl interpreter terminates
例如,您可以简单地在类中放置以下方法 DESTROY -
For Example, you can simply put the following method DESTROY in your class −
package MyClass;
...
sub DESTROY {
print "MyClass::DESTROY called\n";
}
Object Oriented Perl Example
这里还有另一个很好的示例,它将帮助您了解 Perl 的面向对象概念。将此源代码放入任何 perl 文件中并执行它。
Here is another nice example, which will help you to understand Object Oriented Concepts of Perl. Put this source code into any perl file and execute it.
#!/usr/bin/perl
# Following is the implementation of simple Class.
package MyClass;
sub new {
print "MyClass::new called\n";
my $type = shift; # The package/type name
my $self = {}; # Reference to empty hash
return bless $self, $type;
}
sub DESTROY {
print "MyClass::DESTROY called\n";
}
sub MyMethod {
print "MyClass::MyMethod called!\n";
}
# Following is the implemnetation of Inheritance.
package MySubClass;
@ISA = qw( MyClass );
sub new {
print "MySubClass::new called\n";
my $type = shift; # The package/type name
my $self = MyClass->new; # Reference to 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";
}
# Here is the main program using above classes.
package main;
print "Invoke MyClass method\n";
$myObject = MyClass->new();
$myObject->MyMethod();
print "Invoke MySubClass method\n";
$myObject2 = MySubClass->new();
$myObject2->MyMethod();
print "Create a scoped object\n";
{
my $myObject2 = MyClass->new();
}
# Destructor is called automatically here
print "Create and undef an object\n";
$myObject3 = MyClass->new();
undef $myObject3;
print "Fall off the end of the script...\n";
# Remaining destructors are called automatically here
当我们执行以上程序时,它会产生以下结果 −
When we execute above program, it produces the following result −
Invoke MyClass method
MyClass::new called
MyClass::MyMethod called!
Invoke MySubClass method
MySubClass::new called
MyClass::new called
MyClass::MyMethod called!
MySubClass::MyMethod called!
Create a scoped object
MyClass::new called
MyClass::DESTROY called
Create and undef an object
MyClass::new called
MyClass::DESTROY called
Fall off the end of the script...
MyClass::DESTROY called
MySubClass::DESTROY called