【转载】Perl异常处理方法总结

程序脚本在运行过程中,总会碰到这样那样的问题,我们会预知一些问题并为其准备好处理代码,而有一些不能预知。好的程序要能尽可能多的处理可能出现的异常问题,本文就总结了一些方法来解决这些异常,当然perl在这个处理了不及其它同类语言,但也不会差到那里。在开始前,我们先盘点一些关于perl的优缺点。

0. 历史太悠久了。你可以在1997年的计算机上找到perl5.0。(只是吐槽一下,历史悠久没什么不好,与时俱进才是关键)

1. 不回收循环垃圾(这是个硬伤,也许和Perl设计的初衷有关,小脚本影响不大;但因为这个,perl与稍微大一点的程序就无缘了)

2. 容错(如字符串和数值的隐式转换等),但换句话说就是对错误过于放纵,程序产生错误结果而不是报错。

3. 一件事有很多方法做(TIMTOWTDY),但换句话说就是做一件事没有“一种明显的做法”。比如数组的长度是$#somearray+1。为什么是加一呢?难道不是somearray.length或者len(somearray)吗?

4. 语法比较难懂。语法还处在“脚本语言”(指的是那些随手写随手扔的批处理脚本)的定位上,只是稍微比shell脚本更像传统的编程语言。比如:
4.1 大量使用$符号,以及各种用符号表示的特殊变量。

4.2 函数不带形参列表。

4.3 面向对象支持不好:语法中没有对象语法(没有class等关键字),全靠hash和bless。继承靠ISA,也没有语法支持。

4.4 只有基本的异常处理(perl的eval和die,类似java的try和throw)。但是异常只是一条字符串信息,少了基于对象的异常系统,异常处理总是不如其它语言。

以上这些都会影响可读性和可写性。需要注意的是,人的大脑同时可以关注的信息是有限的。如果写业务逻辑,却偏偏要不断关注实现细节(比如使用package, hash, ISA, bless来实现面向对象),程序员的思路就会不断地被这些细节打乱,急剧降低编程速度,还会不断犯错误,甚至为了简单性而牺牲效率甚至正确性。

一个高级的语言就是对高级的概念的抽象,使得程序员可以将思维从下层的细节中脱离出来(Separation of Concern)。Perl作为文本批处理用的脚本语言是够的,可以做很多shell不擅长的字符串处理(正则表达式很赞)和计算,这在当时也是好的。但是对于稍微大一些的程序,甚至需要面向对象的时候,Perl就不合适了。

Perl可以写出很简短的代码(谷歌一下“code golf”),在这一点上Ruby更像Perl。下面就介绍一些让Perl脚本编写的更加规范,甚至在出现错误时能得到很好的处理的方法技巧。

打开约束指令,让编码更规范

如果你使用perl5.10 或更高的版本,可以显示的指定当前Perl版本号来自动打开约束指令。

use 5.012; #自动启用use strict 指令
use v5.10; #自动布严格模式

之前的版本通过添加下边的指令:
use strict;

通过启用约束指令,编程时常见的错误很容易暴露出来。而启用warnings指令的话,还能捕获一些其他不是很紧要的问题。

如果担心原先的程序启用strict后程序不正常运行,则可以在实际修改代码前,先在命令行上试着启用strict看看:
perl -Mstrict freeoa_program.pl

Perl的约束集包括vars(变量),subs(子程序)和refs(引用)这三部分,通常这三种约束同时使用。

在很多情况下,系统调用可能会失败;例如,尝试打开不存在的文件,或者删除某个仍含有文件的目录,或者尝试读取没有读权限的文件。在前面的示例中,我们已经用到了die函数,详细讨论有关错误处理和错误处理函数的相关内容。这些函数包括die函数、warn函数和eval函数。

die函数用于在命令或文件句柄失败时退出Perl脚本。

warn函数类似于die函数,但它不会退出脚本。

eval函数具有多种用途,但它主要还是用于异常处理。

读者想必还记得短路运算符&&和||,这两个运算符首先会求其左侧操作数的值,然后才会求其右侧操作数的值。如果&&左侧操作数值为true,则求其右侧的操作数。如果||左侧操作数的值为false,这才求其右侧的操作数。

Perl 5提供的Carp模块扩展了die和warn的功能

对一段代码中如果有一句出现异常,但事先并不知道是哪一句,怎样进行异常的捕获?

eval{.........};#捕获运行时的错误

if([email protected]){........};#进行错误处理

通过使用 Perl 的 eval 语句来分析错误,使用标准方法来处理 Perl 错误,请使用以下语法:
eval {enter statements you want to monitor};

在运行时,如果 Perl 引擎在 eval 块内的语句中遇到错误,那么它会跳过 eval 块的剩余部分,并为对应的错误文本设置 [email protected]。例如:
eval{$objectName->MethodName();};
if ([email protected]){ 
 print "Error using MethodName method. Error: [email protected]\n"; 

else{
 # continue without error ... 
}

某些预期通常失败的函数不包含在此范围内。尤其是验证和设置字段函数返回错误说明,而不是抛出异常。这样可拦截内部中断信号后对其进行处理,而不是简单地让程序对异常按默认方法进行处理。

The recommended way to do some things, like timeouts, is through an eval/die pair. However, I‘ve noticed that if you set $SIG{__DIE__} to do some custom reporting, like in:
 $SIG{__WARN__} = sub { ... };   # custom error report
 $SIG{__DIE__} = sub { &{$SIG{__WARN__}; exit(1); };
 # custom error report and terminate

eval {
 $SIG{ALRM} = sub { die "timeout\n"; };
 alarm 20;
 ...
 alarm 0;
}

"die" isn‘t caught! It remains fatal!

The only way around this (that I found), is to clear $SIG{__DIE__} in the eval blok:
eval{
 local($SIG{__DIE__});   #back to standard Perl die
 ...
}

Question: is there another way to terminate a __DIE__ sub, that is NOT fatal in eval? "die" doesn‘t die in eval, but ONLY if you didn‘t set $SIG{__DIE__} yourself (even outside of the eval block). Surely, this can‘t be the way it‘s supposed to be?

你最好要使用Try::Tiny模块来处理这些问题,这将帮助你避免一些老的版本里的陷阱。

use Try::Tiny;
try{
 die "foo";
}catch{
 warn "caught error: $_";
};

有时我们常常写多个 open ,然后还要写上多次 die 像下面,读一个文件,然后写一个文件,有时我写的 open 会超过 4 个,要写很多次 die 这时非常麻烦。我们如果直接 use autodie 就直接能解决所有问题,所有的 die 的地方都能自动实现。

open my $fh, ‘<‘, $in or die "$!";
open my $fh, ‘>‘, $out or die "$!";

autodie简化错误处理

autodie编译指令(从5.10.1起开始自带,也可以直接从CPAN安装)

默认情况下,autodie会对它能起作用的所有函数生效。如果只是希望对某些特定函数起作用,可以将各个函数的名字或一组函数的组名列出来告诉autodie:
use autodie qw(open close); #只对特定函数生效
use autodie qw(:filesys); #只对 某组函数生效

在autodie捕获错误时,它会把[email protected]设置为autodie::exception对象,而[email protected]就是表示eval错误变量

加上 autodie 以后就成了
use autodie
open my $fh, ‘<‘, $fin;
open my $fh, ‘>‘, $fout;

有了这个方便多了,有时我们常常不想让程序 die 了后退出,想抓到原因,得使用 eval 然后来检查 [email protected],像下面这样。

use autodie;
eval{ 
 open my $fh, ‘<‘, $in; 
 # .....
}
if([email protected]){
 #TODO
}

eval{ 
 open my $fh, ‘>‘, $out;
}

if([email protected]){
 #TODO
}

还好上次只有二个 open 。是不是感觉很痛苦,要是 open 之类会 die 的更加多点的话。另外,有没有发现,只要第一个 open 失败,第二个 if ([email protected]) 永远会失败,因为 [email protected] 的标记下面也检查同样的变量。这时使用 Try::Tiny 中的 try catch 吧。

Try::Tiny模块配合使用

Perl 没有内置的异常处理机制,所以最合适的方法就是使用Try::Tiny模块。虽然CPAN中处理异常的模块很多,但是这个模块最为轻巧,使用起来也没有过多的依赖关系。

use autodie;
use Try::Tiny;
# handle errors with a catch handler
try{
 die "foo";
}catch{
 warn "caught error: $_"; # not [email protected]
};

注意:catch 代码以分号结尾的,是一个表达式。另外它会将出错的信息保存在变量$_而不是[email protected]中。

这时使用很方便

use autodie;
use Try::Tiny;
try { 
 open my $fh, ‘<‘, $in; 
 # .....
 open my $fh, ‘>‘, $out;
 # .....
}
catch {
 print "Error $_\n";
}

有时我们还可以在这个地方使用‘try catch‘做程序流程控制
use autodie;
use Try::Tiny;

try { 
 &sub1();
 &sub2();
 &sub3();
}
catch {
 &suba();
 &subb();
 &subc();
}

像上面,只要在 sub1, sub2, sub3 任意一个子函数 die 出来,这个流程就认为出错,就做其它的另一种方案的流程 suba,subb,subc。

时间: 2024-08-26 12:24:34

【转载】Perl异常处理方法总结的相关文章

PL/SQL异常处理方法

1:什么是异常处理: PL/SQL提供一个功能去处理异常,在PL/SQL块中叫做异常处理,使用异常处理我们能够测试代码和避免异常退出. PL/SQL异常信息包含三个部分: 1:异常类型 2:错误代码 3:错误信息 通过处理异常我们能够确保PL/SQL块不突然的异常退出. 2:异常处理的结构 DECLARE Declaration section BEGIN Exception section EXCEPTION WHEN ex_name1 THEN -Error handling stateme

转载 50种方法优化SQL Server数据库查询

原文地址 http://www.cnblogs.com/zhycyq/articles/2636748.html 50种方法优化SQL Server数据库查询 查询速度慢的原因很多,常见如下几种: 1.没有索引或者没有用到索引(这是查询慢最常见的问题,是程序设计的缺陷) 2.I/O吞吐量小,形成了瓶颈效应. 3.没有创建计算列导致查询不优化. 4.内存不足 5.网络速度慢 6.查询出的数据量过大(可以采用多次查询,其他的方法降低数据量) 7.锁或者死锁(这也是查询慢最常见的问题,是程序设计的缺陷

day15——异常常用形式、异常处理方法、raise关键字的使用

异常既是一个事件,该事件会在程序执行过程中发生,影响了程序的正常执行. 一般情况下,在Python无法正常处理程序时就会发生一个异常.异常是Python对象,表示一个错误.当Python脚本发生异常时我们需要捕获处理它,否则程序会终止执行.最常用异常的形式 a) 异常的常用形式 我们平时工作中最常用到的异常处理的形式: try: 正常的操作 .......... except 发生异常,执行这块代码 ...... else: 如果没有异常执行这场代码 finally: 不管如何,最后一定要执行的

MySQL定义异常和异常处理方法

在MySQL中,特定异常需要特定处理.这些异常可以联系到错误,以及子程序中的一般流程控制.定义异常是事先定义程序执行过程中遇到的问题,异常处理定义了在遇到问题时对应当采取的处理方式,并且保证存储过程或者函数在遇到错误时或者警告时能够继续执行. 1 异常定义 1.1 语法 DECLARE condition_name CONDITION FOR [condition_type]; 1.2 说明 condition_name参数表示异常的名称: condition_type参数表示条件的类型,con

IOS捕获异常,常用的异常处理方法。

前言:在开发APP时,我们通常都会需要捕获异常,防止应用程序突然的崩溃,防止给予用户不友好的一面.其实OBJECT-C的异常处理方法和JAVA的雷同,懂JAVA的朋友一看就懂.我为什么要写这篇博文呢?因为我发现百度上的介绍方法,很多都不是我想要的,而我想要的又说得不清楚,重点是大家都是直接复制别人的代码...于是不多说,大家往下看--- 以下程序已测试并通过: 设备:IOS8模拟器中 开发工具:XCode6.1 使用@try.catch捕获异常: 以下是最简单的代码写法,其中@finally可以

iOS捕获异常,常用的异常处理方法

本文转载至 http://www.cocoachina.com/ios/20141229/10787.html 前言:在开发APP时,我们通常都会需要捕获异常,防止应用程序突然的崩溃,防止给予用户不友好的体验.其实Objective-C的异常处理方法和JAVA的雷同,懂JAVA的朋友一看就懂.我为什么要写这篇博文呢?因为我发现百度上的介绍方法,很多都不是我想要的,而我想要的又说得不清楚,重点是大家都是直接复制别人的代码...于是不多说,大家往下看--- 以下程序已测试并通过: 设备:iOS 8模

转载-&gt;C#异常处理

C# 异常处理 异常是在程序执行期间出现的问题.C# 中的异常是对程序运行时出现的特殊情况的一种响应,比如尝试除以零. 异常提供了一种把程序控制权从某个部分转移到另一个部分的方式.C# 异常处理时建立在四个关键词之上的:try.catch.finally 和 throw. try:一个 try 块标识了一个将被激活的特定的异常的代码块.后跟一个或多个 catch 块. catch:程序通过异常处理程序捕获异常.catch 关键字表示异常的捕获. finally:finally 块用于执行给定的语

转载 JQuery.data()方法学习

转载原地址  http://hanchaohan.blog.51cto.com/2996417/1271551 转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://hanchaohan.blog.51cto.com/2996417/1271551 1 <!doctype html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 <title&g

[转载]Android应用方法隐藏及反调试技术浅析

本文转载自: http://drops.wooyun.org/tips/9471 0x00 前言 Android应用的加固和对抗不断升级,单纯的静态加固效果已无法满足需求,所以出现了隐藏方法加固,运行时动态恢复和反调试等方法来对抗,本文通过实例来分析有哪些对抗和反调试手段. 0x01 对抗反编译 首先使用apktool进行反编译,发现该应用使用的加固方式会让apktool卡死,通过调试apktool源码(如何调试apktool可参见前文<Android应用资源文件格式解析与保护对抗研究>),发