- Perl基礎
- Perl - 首頁
- Perl - 簡介
- Perl - 環境
- Perl - 語法概述
- Perl - 資料型別
- Perl - 變數
- Perl - 標量
- Perl - 陣列
- Perl - 雜湊表
- Perl - IF...ELSE
- Perl - 迴圈
- Perl - 運算子
- Perl - 日期與時間
- Perl - 子程式
- Perl - 引用
- Perl - 格式
- Perl - 檔案I/O
- Perl - 目錄
- Perl - 錯誤處理
- Perl - 特殊變數
- Perl - 編碼規範
- Perl - 正則表示式
- Perl - 傳送郵件
- Perl高階
- Perl - 套接字程式設計
- Perl - 面向物件
- Perl - 資料庫訪問
- Perl - CGI程式設計
- Perl - 包與模組
- Perl - 程序管理
- Perl - 嵌入式文件
- Perl - 函式引用
- Perl有用資源
- Perl - 問答
- Perl - 快速指南
- Perl - 有用資源
- Perl - 討論
Perl面向物件程式設計
我們已經學習了Perl中的引用以及Perl匿名陣列和雜湊表。Perl中的面向物件概念很大程度上基於引用、匿名陣列和雜湊表。讓我們開始學習Perl面向物件程式設計的基本概念。
物件基礎
從Perl如何處理物件的角度出發,解釋三個主要術語:物件、類和方法。
在Perl中,**物件**僅僅是對知道自身所屬類的某種資料型別的引用。物件儲存為標量變數中的引用。因為標量只包含對物件的引用,所以同一個標量可以在不同的類中儲存不同的物件。
在Perl中,**類**是一個包含建立和操作物件所需相應方法的包。
在Perl中,**方法**是一個在包內定義的子程式。方法的第一個引數是物件引用或包名,取決於方法是影響當前物件還是類。
Perl提供了一個**bless()**函式,用於返回最終成為物件的引用。
定義類
在Perl中定義類非常簡單。在最簡單的形式下,類對應於Perl包。要在Perl中建立類,我們首先建立一個包。
包是使用者定義變數和子程式的自包含單元,可以反覆重用。
Perl包在Perl程式中提供了一個獨立的名稱空間,使子程式和變數保持獨立,避免與其他包中的那些衝突。
要在Perl中宣告名為Person的類,我們這樣做:
package Person;
包定義的作用域擴充套件到檔案的末尾,或者直到遇到另一個package關鍵字。
建立和使用物件
要建立一個類的例項(一個物件),我們需要一個物件建構函式。這個建構函式是在包內定義的方法。大多數程式設計師選擇將這個物件建構函式方法命名為new,但在Perl中可以使用任何名稱。
你可以在Perl中使用任何型別的Perl變數作為物件。大多數Perl程式設計師選擇陣列或雜湊表的引用。
讓我們使用Perl雜湊引用為Person類建立建構函式。建立物件時,需要提供一個建構函式,它是一個包內的子程式,返回一個物件引用。物件引用是透過將對包的類的引用進行bless建立的。例如:
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;
}
現在讓我們看看如何建立物件。
$object = new Person( "Mohammad", "Saleem", 23234345);
如果你不想為任何類變數賦值,可以在建構函式中使用簡單的雜湊表。例如:
package Person;
sub new {
my $class = shift;
my $self = {};
bless $self, $class;
return $self;
}
定義方法
其他面向物件的語言具有資料安全的概念,以防止程式設計師直接更改物件資料,並且它們提供訪問器方法來修改物件資料。Perl沒有私有變數,但我們仍然可以使用輔助方法的概念來操作物件資料。
讓我們定義一個輔助方法來獲取人的名字:
sub getFirstName {
return $self->{_firstName};
}
另一個設定人名的輔助函式:
sub setFirstName {
my ( $self, $firstName ) = @_;
$self->{_firstName} = $firstName if defined($firstName);
return $self->{_firstName};
}
現在讓我們看看完整的例子:將Person包和輔助函式放在Person.pm檔案中。
#!/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物件,如下所示:
#!/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";
當我們執行上述程式時,它會產生以下結果:
First Name is Mohammad Last Name is Saleem SSN is 23234345 Before Setting First Name is : Mohammad Before Setting First Name is : Mohd.
繼承
面向物件程式設計有一個非常有用且有用的概念叫做繼承。繼承簡單來說就是父類的屬性和方法將可用於子類。因此,您不必一遍又一遍地編寫相同的程式碼,您可以繼承父類。
例如,我們可以有一個Employee類,它繼承自Person類。這被稱為“isa”關係,因為員工是人。Perl有一個特殊的變數@ISA來輔助此操作。@ISA控制(方法)繼承。
使用繼承時,需要考慮以下重要事項:
Perl在指定物件的類中搜索給定的方法或屬性,即變數。
Perl搜尋在物件類的@ISA陣列中定義的類。
如果在步驟1或2中找不到方法,則Perl使用AUTOLOAD子程式(如果在@ISA樹中找到)。
如果仍然找不到匹配的方法,則Perl會在標準Perl庫的一部分UNIVERSAL類(包)中搜索該方法。
如果仍然找不到方法,則Perl放棄並引發執行時異常。
因此,要建立一個新的Employee類來繼承Person類的所有方法和屬性,我們只需編寫如下程式碼:將此程式碼放入Employee.pm中。
#!/usr/bin/perl package Employee; use Person; use strict; our @ISA = qw(Person); # inherits from Person
現在Employee類繼承了Person類中的所有方法和屬性,您可以按如下方式使用它們:使用main.pl檔案進行測試:
#!/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";
當我們執行上述程式時,它會產生以下結果:
First Name is Mohammad Last Name is Saleem SSN is 23234345 Before Setting First Name is : Mohammad Before Setting First Name is : Mohd.
方法重寫
子類Employee繼承了父類Person的所有方法。但是,如果您想在子類中重寫這些方法,則可以透過提供您自己的實現來做到這一點。您可以在子類中新增其他函式,或者新增或修改父類中現有方法的功能。這可以按如下方式完成:修改Employee.pm檔案。
#!/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物件並執行它。
#!/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";
當我們執行上述程式時,它會產生以下結果:
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.
預設自動載入
Perl提供了一個在其他程式語言中找不到的功能:預設子程式。這意味著,如果您定義了一個名為**AUTOLOAD()**的函式,則對未定義子程式的所有呼叫將自動呼叫AUTOLOAD()函式。缺失子程式的名稱可在該子程式中作為$AUTOLOAD訪問。
預設自動載入功能對於錯誤處理非常有用。這是一個實現AUTOLOAD的示例,您可以根據自己的方式實現此函式。
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);
}
}
解構函式和垃圾收集
如果您以前使用過面向物件程式設計,那麼您將意識到需要建立一個**解構函式**來釋放使用完物件後分配給該物件的記憶體。Perl會在物件超出作用域後自動執行此操作。
如果您想實現解構函式(應負責關閉檔案或執行一些額外的處理),則需要定義一個名為**DESTROY**的特殊方法。此方法將在Perl釋放分配給它的記憶體之前立即在物件上呼叫。在所有其他方面,DESTROY方法與任何其他方法一樣,您可以在此方法中實現任何您想要的邏輯。
解構函式方法只是一個名為DESTROY的成員函式(子程式),它將在以下情況下自動呼叫:
- 當物件引用的變數超出作用域時。
- 當物件引用的變數被undef時。
- 當指令碼終止時
- 當perl直譯器終止時
例如,您可以簡單地將以下DESTROY方法放入您的類中:
package MyClass;
...
sub DESTROY {
print "MyClass::DESTROY called\n";
}
Perl面向物件程式設計示例
這是一個很好的例子,它將幫助您理解Perl的面向物件概念。將此原始碼放入任何Perl檔案中並執行它。
#!/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
當我們執行上述程式時,它會產生以下結果:
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