Amazon Best VPN GoSearch

OnWorks 网站图标

perlobj - 云端在线

在 OnWorks 免费托管服务提供商中通过 Ubuntu Online、Fedora Online、Windows 在线模拟器或 MAC OS 在线模拟器运行 perlobj

这是命令 perlobj,可以使用我们的多个免费在线工作站之一在 OnWorks 免费托管服务提供商中运行,例如 Ubuntu Online、Fedora Online、Windows 在线模拟器或 MAC OS 在线模拟器

程序:

您的姓名


perlobj - Perl 对象引用

商品描述


本文档为 Perl 的面向对象特性提供了参考。 如果你是
要查找 Perl 中面向对象编程的介绍,请参阅 perlootut。

为了理解 Perl 对象,您首先需要理解 Perl 中的引用。 看
perlref 了解详情。

本文档从头开始描述了 Perl 的所有面向对象 (OO) 特性。 如果
你只是想写一些你自己的面向对象的代码,你可能
使用 perlootut 中描述的来自 CPAN 的对象系统之一可以更好地提供服务。

如果您想编写自己的对象系统,或者您需要维护代码
从头开始实现对象,那么本文档将帮助您准确了解如何
Perl 是面向对象的。

有几个基本原则定义了面向对象的 Perl:

1. 对象只是一个知道它属于哪个类的数据结构。

2. 一个类就是一个包。 一个类提供了期望操作的方法
对象。

3. 方法只是一个子程序,它需要一个对象(或包
名称,对于类方法)作为第一个参数。

让我们深入了解这些原则中的每一个。

An 摆件 is 只是 a 时间 结构
与许多其他支持面向对象的语言不同,Perl 不提供任何
用于构造对象的特殊语法。 对象只是 Perl 数据结构
(散列、数组、标量、文件句柄等)已明确与
特定班级。

该显式关联是由内置的“bless”函数创建的,通常是
内使用 构造函数 类的子程序。

这是一个简单的构造函数:

包文件;

子新{
我的 $class = shift;

返回祝福 {}, $class;
}

“新”这个名字并不特别。 我们可以将构造函数命名为其他名称:

包文件;

子负载{
我的 $class = shift;

返回祝福 {}, $class;
}

OO 模块的现代约定是始终使用“new”作为
构造函数,但没有要求这样做。 任何祝福数据的子程序
将结构转换为类是 Perl 中的有效构造函数。

在前面的示例中,“{}”代码创建了对空匿名哈希的引用。
“bless”函数然后获取该引用并将散列与中的类相关联
$类。 在最简单的情况下, $class 变量最终将包含字符串
“文件”。

我们还可以使用一个变量来存储对正在使用的数据结构的引用
祝福作为我们的目标:

子新{
我的 $class = shift;

我的 $self = {};
保佑 $self, $class;

返回 $self;
}

一旦我们祝福了 $self 引用的哈希,我们就可以开始调用它的方法。 这个
如果您想将对象初始化放在其自己的单独方法中,则很有用:

子新{
我的 $class = shift;

我的 $self = {};
保佑 $self, $class;

$self->_initialize();

返回 $self;
}

由于对象也是一个hash,你可以把它当作一个,用它来存储数据
与对象相关联。 通常,类中的代码可以将散列视为
可访问的数据结构,而类外的代码应始终将对象视为
不透明。 这就是所谓的 封装. 封装意味着对象的用户
不必知道它是如何实现的。 用户只需调用记录的方法
目的。

但是请注意,(与大多数其他 OO 语言不同)Perl 不确保或强制执行
以任何方式封装。 如果你想让对象实际上 be 不透明你需要安排
为此你自己。 这可以通过多种方式完成,包括使用“由内而外”
对象”或来自 CPAN 的模块。

对象 有福了; 变量

当我们祝福某事时,我们并不是祝福包含引用的变量
那件事,我们也不祝福变量存储的引用; 我们祝福
变量所指的事物(有时称为 指称对象)。 这是最好的
用此代码演示:

使用 Scalar::Util 'blessed';

我的 $foo = {};
我的 $bar = $foo;

保佑 $foo, 'Class';
打印祝福( $bar )// '没有祝福'; # 打印“类”

$bar = "其他值";
打印祝福( $bar )// '没有祝福'; # 打印“没有祝福”

当我们对一个变量调用“bless”时,实际上是在祝福底层的数据结构
变量所指的。 我们不祝福引用本身,也不祝福变量
包含该引用。 这就是为什么第二次调用 "blessed( $bar )" 会返回
错误的。 此时 $bar 不再存储对对象的引用。

您有时会看到较旧的书籍或文档提到“祝福参考”或
将对象描述为“有福的参考”,但这是不正确的。 这不是参考
那是被祝福的对象; 它是引用所指的事物(即所指对象)。

A 增益级 is 只是 a 小包装
Perl 没有为类定义提供任何特殊的语法。 一个包只是一个
包含变量和子程序的命名空间。 唯一的区别是在一个班级里,
子程序可能需要一个对象的引用或一个类的名称作为第一个
争论。 这纯粹是一个约定问题,因此一个类可能包含方法和
子程序 对对象或类进行操作。

每个包都包含一个名为@ISA 的特殊数组。 @ISA 数组包含一个列表
班级的父班级,如果有的话。 这个数组在 Perl 进行方法解析时被检查,
我们稍后会介绍。

可以手动设置@ISA,您可能会在较旧的 Perl 代码中看到这一点。 老得多
代码也使用基本编译指示。 对于新代码,我们建议您使用 parent pragma
宣布你的父母。 此编译指示将负责设置@ISA。 它也会加载
父类并确保包不会从自身继承。

不管父类是如何设置的,包的@ISA 变量将包含一个列表
那些父母。 这只是一个标量列表,每个标量都是一个字符串
对应一个包名。

所有类都隐式地继承自 UNIVERSAL 类。 通用类是
由 Perl 核心实现,并提供了几种默认方法,例如“isa()”,
“can()”和“VERSION()”。 “通用”类将 决不要 出现在包的@ISA 中
变量。

Perl的 仅由 提供方法继承作为内置功能。 属性继承是
留下类来实现。 有关详细信息,请参阅“写入访问器”部分。

A 付款方式 is 只是 a 子程序
Perl 不提供任何用于定义方法的特殊语法。 一个方法只是一个
常规子程序,并用“sub”声明。 一个方法的特别之处在于它
期望接收一个对象或一个类名作为它的第一个参数。

Perl的 为方法调用提供特殊语法,即“->”运算符。 我们将涵盖
稍后会更详细地说明这一点。

您编写的大多数方法都希望对对象进行操作:

子保存{
我的 $self = shift;

打开我的 $fh, '>', $self->path() 或者死 $!;
打印 {$fh} $self->data() 否则死 $!;
关闭 $fh 或死 $!;
}

付款方式 调用
在对象上调用方法被写为“$object->method”。

方法调用(或箭头)运算符的左侧是对象(或类
名称),右侧是方法名称。

我的 $pod = File->new('perlobj.pod', $data);
$pod->save();

取消引用引用时也使用“->”语法。 看起来是一样的
运算符,但这是两种不同的操作。

调用方法时,箭头左侧的东西作为第一个传递
方法的论据。 这意味着当我们调用“Critter->new()”时,“new()”方法
接收字符串“Critter”作为它的第一个参数。 当我们调用“$fred->speak()”时,
$fred 变量作为第一个参数传递给“speak()”。

就像任何 Perl 子程序一样,@_ 中传递的所有参数都是
原论。 这包括对象本身。 如果你直接分配给 $_[0] 你
将更改保存对象引用的变量的内容。 我们
建议您不要这样做,除非您确切地知道自己在做什么。

Perl 通过查看箭头的左侧知道该方法在哪个包中。 如果
左边是一个包名,它在那个包中查找方法。 如果左边
手边是一个对象,然后Perl在该对象拥有的包中查找方法
被祝福进入。

如果左侧既不是包名也不是对象,则方法调用将
导致错误,但请参阅“方法调用变体”部分以了解更多细微差别。

遗产
我们已经讨论过特殊的@ISA 数组和父编译指示。

当一个类从另一个类继承时,父类中定义的任何方法都是
可用于子类。 如果您尝试在一个不存在的对象上调用方法
在它自己的类中定义,Perl 也会在它可能的任何父类中查找该方法
有。

包文件::MP3;
使用父“文件”; # 设置@File::MP3::ISA = ('File');

我的 $mp3 = File::MP3->new('Andvari.mp3', $data);
$mp3->save();

由于我们没有在“File::MP3”类中定义“save()”方法,Perl 将查看
“File::MP3”类的父类来查找“save()”方法。 如果 Perl 找不到
“save()”方法在继承层次结构中的任何地方,它都会死。

在这种情况下,它会在“File”类中找到“save()”方法。 注意对象通过
在这种情况下,“save()”仍然是一个“File::MP3”对象,即使该方法在
“文件”类。

我们可以在子类中覆盖父类的方法。 当我们这样做时,我们仍然可以调用
带有“SUPER”伪类的父类的方法。

子保存{
我的 $self = shift;

说“准备摇滚”;
$self->SUPER::save();
}

“SUPER”修饰符可以 仅由 用于方法调用。 您不能将其用于常规
子程序调用或类方法:

超级::保存($东西); # 失败:在包 SUPER 中查找 save() sub

超级->保存($东西); # 失败:在类中查找 save() 方法
# 极好的

$thing->SUPER::save(); # 好的:在父级中寻找 save() 方法
# 类

创新中心 is 解决

“SUPER”伪类是从进行调用的包中解析出来的。 这是 而不去
根据对象的类解析。 这很重要,因为它让方法在
深层继承层次结构中的不同级别各自正确地调用了各自的
父方法。

套餐A;

子新{
返回祝福{},移位;
}

子说{
我的 $self = shift;

说“A”;
}

包B;

使用 parent -norequire, 'A';

子说{
我的 $self = shift;

$self->SUPER::speak();

说“B”;
}

包C;

使用 parent -norequire, 'B';

子说{
我的 $self = shift;

$self->SUPER::speak();

说“C”;
}

我的 $c = C->new();
$c->speak();

在这个例子中,我们将得到以下输出:

A
B
C

这演示了如何解析“SUPER”。 即使对象被祝福进入“C”
类,“B”类中的“speak()”方法仍然可以调用“SUPER::speak()”并期待它
正确查看“B”的父类(即方法调用所在的类),而不是
“C”的父类(即对象所属的类)。

在极少数情况下,这种基于包的解决方案可能会成为问题。 如果你复制一个
从一个包到另一个包的子程序,将根据
原包装。

遗产

多重继承通常表示一个设计问题,但 Perl 总是给你足够的
如果你要求的话,可以用绳子吊死自己。

要声明多个父级,您只需将多个类名传递给“使用父级”:

包 MultiChild;

使用父 'Parent1', 'Parent2';

付款方式 分辨率 下单

方法解析顺序仅在多重继承的情况下很重要。 如果是
单继承,Perl 简单地查找继承链以找到一个方法:

祖父母
|
父母
|
儿童

如果我们在“Child”对象上调用一个方法并且该方法没有在“Child”对象中定义
类,Perl 将在“父”类中查找该方法,然后,如有必要,在
“祖父母”班。

如果 Perl 在这些类中的任何一个中找不到该方法,它就会死,并显示一条错误消息。

当一个类有多个父类时,方法查找顺序变得更加复杂。

默认情况下,Perl 对方法进行深度优先的从左到右搜索。 这意味着它
从@ISA 数组中的第一个父级开始,然后搜索其所有父级,
祖父母等。如果它找不到方法,则转到下一个父级
原始类的@ISA 数组并从那里搜索。

共享曾祖父
/ \
父亲祖父母 母亲祖父母
\ /
父亲母亲
\ /
儿童

所以给定上图,Perl 将搜索“Child”、“Father”、“PaternalGrandparent”,
“SharedGreatGrandParent”、“Mother”,最后是“MaternalGrandparent”。 这可能是一个
问题,因为现在我们正在寻找“SharedGreatGrandParent” before 我们已经检查了所有
派生类(即在我们尝试“Mother”和“MaternalGrandparent”之前)。

可以使用 mro pragma 请求不同的方法解析顺序。

包子;

使用 mro 'c3';
使用父母'父亲','母亲';

此编译指示可让您切换到“C3”解析顺序。 简单来说,“C3”顺序
确保在子类之前永远不会搜索共享的父类,因此 Perl 将
现在搜索:“Child”、“Father”、“PaternalGrandparent”、“Mother”、“MaternalGrandparent”和
最后是“SharedGreatGrandParent”。 但是请注意,这不是“广度优先”搜索:
所有“父”祖先(共同祖先除外)在任何一个之前搜索
“母亲”祖先被认为是。

C3 顺序还允许您使用“下一个”伪类调用同级类中的方法。
有关此功能的更多详细信息,请参阅 mro 文档。

付款方式 分辨率 高速缓存

当 Perl 搜索一个方法时,它会缓存查找,以便将来调用该方法
不需要再次搜索它。 更改类的父类或添加子程序
到一个类将使该类的缓存无效。

mro pragma 提供了一些直接操作方法缓存的函数。

撰稿 构造函数
正如我们前面提到的,Perl 没有提供特殊的构造函数语法。 这意味着一个
类必须实现自己的构造函数。 构造函数只是一个类方法
返回对新对象的引用。

构造函数还可以接受定义对象的附加参数。 让我们写
我们之前使用的“File”类的真正构造函数:

包文件;

子新{
我的 $class = shift;
我的 ( $path, $data ) = @_;

我的 $self = 祝福 {
路径 => $path,
数据 => $数据,
},$类;

返回 $self;
}

如您所见,我们已将路径和文件数据存储在对象本身中。 记住,下
引擎盖,这个对象仍然只是一个散列。 稍后,我们将编写访问器来操作
这个数据。

对于我们的 File::MP3 类,我们可以检查以确保给定的路径以
“.mp3”:

包文件::MP3;

子新{
我的 $class = shift;
我的 ( $path, $data ) = @_;

die "你不能创建一个没有 mp3 扩展名的 File::MP3\n"
除非 $path =~ /\.mp3\z/;

返回 $class->SUPER::new(@_);
}

这个构造函数让它的父类做实际的对象构造。

Attributes
属性是属于特定对象的一段数据。 不像大多数对象-
面向语言,Perl 不提供特殊的语法或支持来声明和
操纵属性。

属性通常存储在对象本身中。 例如,如果对象是
匿名散列,我们可以使用属性名称将属性值存储在散列中
钥匙。

虽然可以在类外直接引用这些哈希键,但
被认为是使用访问器方法包装对属性的所有访问的最佳实践。

这有几个优点。 访问器可以更容易地改变一个的实现
对象,同时仍保留原始 API。

访问器允许您围绕属性访问添加额外的代码。 例如,你可以
将默认值应用于未在构造函数中设置的属性,或者您可以验证
属性的新值是可接受的。

最后,使用访问器使继承更简单。 子类可以使用访问器
而不必知道父类是如何在内部实现的。

撰稿 存取器

与构造函数一样,Perl 没有提供特殊的访问器声明语法,因此类
必须提供明确写入的访问器方法。 有两种常见的类型
访问器,只读和读写。

一个简单的只读访问器只获取单个属性的值:

子路径{
我的 $self = shift;

返回 $self->{path};
}

读写访问器将允许调用者设置值并获取它:

子路径{
我的 $self = shift;

如果 (@_) {
$self->{path} = shift;
}

返回 $self->{path};
}

An 在旁边 关于我们 更智能 更安全 代码
我们的构造函数和访问器不是很聪明。 他们不检查 $path 是
定义,也不检查 $path 是否是有效的文件系统路径。

手动进行这些检查很快就会变得乏味。 编写一堆访问器
手也异常的乏味。 CPAN 上有很多模块可以帮助你
编写更安全、更简洁的代码,包括我们在 perlootut 中推荐的模块。

付款方式 电话联系 变化
除了“$object->method()”用法之外,Perl 还支持其他几种方法来调用方法
到目前为止我们已经看到了。

付款方式 名称 as 琴弦

Perl 允许您使用包含字符串的标量变量作为方法名称:

我的 $file = File->new( $path, $data );

我的 $method = 'save';
$file->$method();

这与调用“$file->save()”完全一样。 这对写作非常有用
动态代码。 例如,它允许您传递要调用的方法名称作为参数
到另一种方法。

增益级 名称 as 琴弦

Perl 还允许您使用包含字符串作为类名的标量:

我的 $class = '文件';

我的 $file = $class->new( $path, $data );

同样,这允许非常动态的代码。

子程序 案例 as 方法

您还可以使用子例程引用作为方法:

我的 $sub = sub {
我的 $self = shift;

$self->save();
};

$file->$sub();

这完全等同于编写“$sub->($file)”。 你可能会在野外看到这个习语
结合对“can”的调用:

if ( my $meth = $object->can('foo') ) {
$object->$meth();
}

防守 付款方式 电话联系

Perl 还允许您在方法调用中使用取消引用的标量引用。 那是一个
满口,所以让我们看一些代码:

$file->${ \'save' };
$file->${returns_scalar_ref() };
$file->${ \(returns_scalar()) };
$file->${returns_ref_to_sub_ref() };

如果取消引用产生一个字符串,这将起作用 or 一个子程序参考。

付款方式 呼叫 on 文件句柄

在幕后,Perl 文件句柄是“IO::Handle”或“IO::File”类的实例。
一旦你有一个打开的文件句柄,你就可以调用它的方法。 此外,您可以致电
“STDIN”、“STDOUT”和“STDERR”文件句柄上的方法。

打开我的 $fh, '>', 'path/to/file';
$fh->autoflush();
$fh->print('内容');

标准输出->自动刷新();

调用中 增益级 方法
因为 Perl 允许你对包名和子程序名使用裸词,它
有时会错误地解释裸词的含义。 例如,构造
"Class->new()" 可以解释为 "'Class'->new()" 或 "Class()->new()"。 在
英语,第二种解释读作“调用名为 班级(),然后调用
新() 作为返回值的方法 班级()”。如果有一个名为
"Class()" 在当前命名空间中,Perl 总是将 "Class->new()" 解释为
第二种选择:在调用“Class()”返回的对象上调用“new()”

您可以强制 Perl 使用第一种解释(即作为对类的方法调用
以两种方式命名为“Class”)。 首先,您可以在类名后附加一个“::”:

类::->new()

Perl 总是将其解释为方法调用。

或者,您可以引用类名:

'类'-> new()

当然,如果类名是标量 Perl 也会做正确的事情:

我的 $class = 'Class';
$class->new();

间接 摆件 句法

of 这些因素包括原料奶的可用性以及达到必要粉末质量水平所需的工艺。 文件 处理 案件, 使用 of Free Introduction 句法 is 泄气 as it 能够 迷惑 这些因素包括原料奶的可用性以及达到必要粉末质量水平所需的工艺。
Perl的 口译员。 参见 如下。 HPMC胶囊 更多 细节。

Perl 支持另一种称为“间接对象”表示法的方法调用语法。 这个
语法被称为“间接”,因为该方法出现在它被调用的对象之前
上。

此语法可用于任何类或对象方法:

我的 $file = 新文件 $path, $data;
保存 $file;

出于多种原因,我们建议您避免使用此语法。

首先,阅读可能会令人困惑。 在上面的例子中,不清楚“save”是否是一个
“File”类提供的方法或只是一个期望文件对象为的子例程
它的第一个论点。

当与类方法一起使用时,问题更严重。 因为 Perl 允许子程序
名字要写成裸字,Perl 必须猜测方法后面的裸字
是类名或子程序名。 换句话说,Perl 可以将语法解析为
“文件->新($path,$data)” or “新(文件($path,$data))”。

为了解析这段代码,Perl 使用了一种启发式方法,它基于它所看到的包名、什么
当前包中存在子例程,它以前见过的裸词,以及其他
输入。 不用说,启发式可以产生非常令人惊讶的结果!

较旧的文档(和一些 CPAN 模块)鼓励这种语法,特别是对于
构造函数,所以你仍然可以在野外找到它。 但是,我们鼓励您避免
在新代码中使用它。

您可以强制 Perl 将裸字解释为类名,方法是在其后附加“::”,例如
我们之前看到:

我的 $file = 新文件:: $path, $data;

“保佑”, "祝福", “参考”
正如我们之前看到的,一个对象只是一个被祝福成一个类的数据结构
通过“祝福”功能。 "bless" 函数可以接受一个或两个参数:

我的 $object = bless {}, $class;
我的 $object = bless {};

在第一种形式中,匿名哈希被祝福到 $class 中的类中。 在里面
第二种形式,匿名哈希被祝福到当前包中。

强烈不鼓励第二种形式,因为它破坏了子类的能力
重用父的构造函数,但您可能仍然在现有代码中遇到它。

如果你想知道一个特定的标量是否指向一个对象,你可以使用
Scalar::Util 导出的“blessed”函数,随 Perl 核心一起提供。

使用 Scalar::Util 'blessed';

如果(定义有福($thing)){ ... }

如果 $thing 引用一个对象,则此函数返回包的名称
对象已被加持。 如果 $thing 不包含对受祝福对象的引用,
“blessed”函数返回“undef”。

请注意,如果 $thing 已被祝福到一个类中,“blessed($thing)”也将返回 false
名为“0”。 这是一种可能,但相当病态。 不要创建名为“0”的类
除非你知道自己在做什么。

类似地,Perl 的内置“ref”函数处理对受祝福对象的引用
特别。 如果你调用 "ref($thing)" 并且 $thing 持有一个对象的引用,它会
返回对象被祝福到的类的名称。

如果您只想检查变量是否包含对象引用,我们建议
你使用“定义的祝福($对象)”,因为“参考”为所有返回真值
引用,而不仅仅是对象。

- 普及 增益级
所有类都自动继承自 Perl 内置的 UNIVERSAL 类
核。 这个类提供了许多方法,所有这些方法都可以在
类或对象。 您还可以选择在您的类中覆盖其中一些方法。
如果您这样做,我们建议您遵循下面描述的内置语义。

伊萨($类)
“isa”方法返回 true 如果对象是 $class 中的类的成员,或者
$class 子类的成员。

如果您覆盖此方法,它不应抛出异常。

做($角色)
“DOES”方法返回 true 如果它的对象声称执行角色 $role。 经过
默认情况下,这相当于“isa”。 此方法供对象系统使用
实现角色的扩展,如“Moose”和“Role::Tiny”。

您还可以直接在您自己的类中覆盖“DOES”。 如果你覆盖这个
方法,它不应该抛出异常。

可以($方法)
“can”方法检查它被调用的类或对象是否有方法
名为 $method。 这会检查类中的方法及其所有父类。 如果
方法存在,则返回对子例程的引用。 如果没有那么
返回“undef”。

如果您的类通过“AUTOLOAD”响应方法调用,您可能需要重载“can”
返回“AUTOLOAD”方法处理的方法的子例程引用。

如果您覆盖此方法,它不应抛出异常。

版本($需要)
“VERSION”方法返回类(包)的版本号。

如果给出了 $need 参数,那么它将检查当前版本(如定义的
通过包中的 $VERSION 变量)大于或等于 $need; 它会
如果不是这样,那就死吧。 此方法由“VERSION”表单自动调用
使用”。

使用 Package 1.2 qw(一些进口潜艇);
# 暗示:
包->版本(1.2);

我们建议您使用此方法访问另一个包的版本,而不是
直接查看 $Package::VERSION。 您正在查看的包裹可能有
覆盖“版本”方法。

我们也推荐使用这种方法来检查一个模块是否有足够的
版本。 内部实现使用版本模块来确保
正确比较不同类型的版本号。

自动加载
如果调用类中不存在的方法,Perl 将抛出错误。 然而,如果
该类或其任何父类定义了一个“AUTOLOAD”方法,即“AUTOLOAD”
方法被调用。

“AUTOLOAD”作为常规方法被调用,调用者不会知道其中的区别。
无论您的“AUTOLOAD”方法返回什么值,都将返回给调用者。

被调用的完全限定方法名称在 $AUTOLOAD 包中可用
全球为您的班级。 由于这是一个全局的,如果你想引用不带
“strict 'vars'”下的包名前缀,你需要声明它。

# XXX - 这是实现访问器的一种糟糕方式,但它使
# 举个简单的例子。
我们的 $AUTOLOAD;
子自动加载{
我的 $self = shift;

# 从原始方法名称中删除限定符...
我的 $call = $AUTOLOAD =~ s/.*:://r;

# 有这个名字的属性吗?
死“没有这样的属性:$调用”
除非存在 $self->{$call};

# 如果是,返回它...
返回 $self->{$call};
}

sub DESTROY { } #见下文

如果没有“我们的 $AUTOLOAD”声明,此代码将无法在严格的
语用。

正如评论所说,这不是实现访问器的好方法。 它也很慢
到目前为止聪明。 但是,您可能会将其视为在较旧的 Perl 代码中提供访问器的一种方式。
有关 Perl 中 OO 编码的建议,请参阅 perlootut。

如果您的类确实有“AUTOLOAD”方法,我们强烈建议您覆盖
“可以”在你的课堂上也是如此。 你重写的“can”方法应该返回一个子程序
您的“自动加载”响应的任何方法的参考。

破坏者
当对对象的最后一个引用消失时,该对象将被销毁。 如果你只有
对存储在词法标量中的对象的一个​​引用,当该对象被销毁时
标量超出范围。 如果将对象存储在全局包中,则该对象可能不会
超出范围,直到程序退出。

如果你想在对象被销毁时做点什么,你可以定义一个“DESTROY”
类中的方法。 这个方法总是会在适当的时候被 Perl 调用,
除非该方法为空。

这就像任何其他方法一样被调用,将对象作为第一个参数。 它确实
不接收任何额外的参数。 但是,$_[0] 变量在
析构函数,所以你不能给它赋值。

如果您的“DESTROY”方法抛出错误,则此错误将被忽略。 不会发送
到“STDERR”,它不会导致程序死亡。 但是,如果您的析构函数是
在“eval {}”块内运行,则错误将更改 $@ 的值。

因为“DESTROY”方法可以随时调用,你应该本地化任何全局
您可能会在“DESTROY”中更新的变量。 特别是,如果您使用“eval {}”
应该本地化 $@,如果您使用“系统”或反引号,您应该本地化 $?。

如果您在类中定义了“AUTOLOAD”,那么 Perl 将调用您的“AUTOLOAD”来处理
“销毁”方法。 你可以通过定义一个空的“DESTROY”来防止这种情况,就像我们在
自动加载示例。 您还可以检查 $AUTOLOAD 的值并返回而不
当被调用来处理“DESTROY”时做任何事情。

全球覆盖 毁坏

程序前全局销毁时对象销毁的顺序
出口是不可预测的。 这意味着您的对象包含的任何对象可能已经
已被摧毁。 在调用之前,您应该检查是否定义了包含的对象
方法:

子销毁{
我的 $self = shift;

$self->{handle}->close() if $self->{handle};
}

您可以使用“${^GLOBAL_PHASE}”变量来检测您当前是否在全局
破坏阶段:

子销毁{
我的 $self = shift;

返回 if ${^GLOBAL_PHASE} eq 'DESRUCT';

$self->{handle}->close();
}

请注意,此变量是在 Perl 5.14.0 中添加的。 如果要检测全局
在旧版本的 Perl 上销毁阶段,您可以使用“Devel::GlobalDestruction”
CPAN 上的模块。

如果您的“DESTROY”方法在全局销毁期间发出警告,Perl 解释器
将字符串“在全局破坏期间”附加到警告中。

在全局销毁期间,Perl 将始终在 unblessed 之前垃圾收集对象
参考。 有关全局的更多信息,请参阅 perlhacktips 中的“PERL_DESTRUCT_LEVEL”
破坏。

非哈希 对象
到目前为止,所有示例都显示了基于有福散列的对象。 然而,它
可以祝福任何类型的数据结构或指涉对象,包括标量、全局和
子程序。 在野外查看代码时,您可能会看到这种情况。

这是一个模块作为祝福标量的示例:

打包时间;

用严格;
使用警告;

子新{
我的 $class = shift;

我的 $time = 时间;
返回祝福 \$time, $class;
}

子时代{
我的 $self = shift;
返回 ${ $self };
}

我的 $time = Time->new();
打印 $time->epoch();

内而外 对象
过去,Perl 社区试验了一种称为“由内向外对象”的技术。
由内而外的对象将其数据存储在对象的引用之外,并在
对象的唯一属性,例如其内存地址,而不是在对象中
本身。 这具有强制封装对象属性的优点,因为
它们的数据不存储在对象本身中。

这种技术流行了一段时间(并在 Damian Conway 的 Perl的 最棒的
行为准则),但从未实现普遍采用。 CPAN 上的 Object::InsideOut 模块
提供了此技术的全面实现,您可能会看到它或其他
野外的内外模块。

这是该技术的一个简单示例,使用 Hash::Util::FieldHash 核心模块。
此模块已添加到核心以支持由内而外的对象实现。

打包时间;

用严格;
使用警告;

使用 Hash::Util::FieldHash 'fieldhash';

fieldhash 我的 %time_for;

子新{
我的 $class = shift;

我的 $self = bless \( my $object ), $class;

$time_for{$self} = 时间;

返回 $self;
}

子时代{
我的 $self = shift;

返回 $time_for{$self};
}

我的 $time = Time->new;
打印 $time->epoch;

伪哈希
伪哈希特性是早期版本的 Perl 中引入的实验性特性
并在 5.10.0 中删除。 伪哈希是一个数组引用,可以使用
命名键就像一个散列。 您可能会遇到一些使用它的野外代码。 见
字段 pragma 以获取更多信息。

使用 onworks.net 服务在线使用 perlobj


免费服务器和工作站

下载 Windows 和 Linux 应用程序

Linux 命令

Ad




×
广告
❤️在这里购物、预订或购买——免费,有助于保持服务免费。