Perl 错误处理
die 和 warn
die - 致命错误
perl
# 基本使用
open(my $fh, '<', 'nonexistent.txt')
or die "Cannot open file: $!";
# 带行号
die "Error occurred at line " . __LINE__ . "\n";
# 包含文件名
die "Error in file " . __FILE__ . " at line " . __LINE__ . "\n";warn - 警告
perl
# 基本使用
warn "This is a warning message\n";
# 带条件
warn "Value is negative: $value\n" if $value < 0;
# 在警告中包含更多信息
warn "Warning at " . __FILE__ . " line " . __LINE__ . "\n";$! - 系统错误消息
perl
open(my $fh, '<', 'file.txt')
or die "Cannot open file: $!";
# $! 包含系统错误描述
# 例如:"No such file or directory"$? - 子进程退出状态
perl
system("ls -l");
if ($? != 0) {
die "Command failed with status: $?";
}eval - 错误捕获
基本 eval
perl
# 捕获致命错误
eval {
open(my $fh, '<', 'nonexistent.txt')
or die "Cannot open file";
};
if ($@) {
print "Error: $@\n";
}返回值
perl
my $result = eval {
# 可能出错的代码
10 / 0;
};
if ($@) {
print "Error: $@\n";
} else {
print "Result: $result\n";
}嵌套 eval
perl
eval {
eval {
die "Inner error";
};
if ($@) {
warn "Caught inner error: $@";
die "Outer error";
}
};
if ($@) {
print "Outer error: $@\n";
}自定义错误处理
使用信号处理器
perl
# 处理 INT 信号(Ctrl+C)
$SIG{INT} = sub {
print "\nInterrupted!\n";
exit;
};
# 处理 TERM 信号
$SIG{TERM} = sub {
print "Terminated!\n";
cleanup();
exit;
};
sub cleanup {
print "Cleaning up...\n";
}使用 DIE 处理器
perl
local $SIG{__DIE__} = sub {
my ($error) = @_;
print "Custom error handler: $error";
# 可以在这里记录日志、发送邮件等
};
die "Something went wrong\n";使用 WARN 处理器
perl
local $SIG{__WARN__} = sub {
my ($warning) = @_;
print "Custom warning handler: $warning";
};
warn "This is a warning\n";Try::Tiny 模块
基本 try/catch
perl
use Try::Tiny;
try {
# 可能出错的代码
open(my $fh, '<', 'file.txt') or die "Cannot open file";
}
catch {
my $error = shift;
print "Caught error: $error\n";
};try/catch/finally
perl
use Try::Tiny;
try {
# 主要代码
open(my $fh, '<', 'file.txt') or die "Cannot open file";
# 处理文件...
}
catch {
my $error = shift;
print "Error: $error\n";
}
finally {
# 总是执行的代码
print "Cleanup\n";
};返回值
perl
use Try::Tiny;
my $result = try {
return 42;
}
catch {
return 0;
};
print "Result: $result\n";异常类
创建简单的异常类
perl
package MyException;
use strict;
use warnings;
sub new {
my ($class, %args) = @_;
return bless \%args, $class;
}
sub message {
my ($self) = @_;
return $self->{message} || "Unknown error";
}
sub code {
my ($self) = @_;
return $self->{code} || 0;
}
1;
# 使用异常类
package main;
use MyException;
eval {
die MyException->new(
message => "Something failed",
code => 500
);
};
if ($@) {
if (ref $@ eq 'MyException') {
print "Exception: " . $@->message() . "\n";
print "Code: " . $@->code() . "\n";
} else {
print "Other error: $@\n";
}
}使用 Exception::Class
perl
use Exception::Class (
'MyApp::Error' => { fields => [qw(action)] },
'MyApp::FileError' => {
isa => 'MyApp::Error',
alias => 'file_error'
},
'MyApp::NetworkError' => {
isa => 'MyApp::Error',
alias => 'network_error'
}
);
# 抛出异常
file_error(
error => "Cannot open file",
action => "read"
);
# 捕获异常
eval {
file_error(error => "Test error");
};
if (my $e = Exception::Class->caught('MyApp::FileError')) {
print "File error: " . $e->error . "\n";
print "Action: " . $e->action . "\n";
} elsif (my $e = Exception::Class->caught('MyApp::Error')) {
print "Error: " . $e->error . "\n";
}日志记录
使用 Log::Log4perl
perl
use Log::Log4perl;
# 配置日志
my $conf = q(
log4perl.rootLogger=DEBUG, LOGFILE, Screen
log4perl.appender.LOGFILE=Log::Log4perl::Appender::File
log4perl.appender.LOGFILE.filename=app.log
log4perl.appender.LOGFILE.layout=PatternLayout
log4perl.appender.LOGFILE.layout.ConversionPattern=%d %p %m %n
log4perl.appender.Screen=Log::Log4perl::Appender::Screen
log4perl.appender.Screen.layout=PatternLayout
log4perl.appender.Screen.layout.ConversionPattern=%d %p %m %n
);
Log::Log4perl::init(\$conf);
my $logger = Log::Log4perl->get_logger();
$logger->debug("Debug message");
$logger->info("Info message");
$logger->warn("Warning message");
$logger->error("Error message");
$logger->fatal("Fatal error message");简单的日志函数
perl
sub log_message {
my ($level, $message) = @_;
my $timestamp = localtime();
printf "[%s] [%s] %s\n", $timestamp, $level, $message;
}
sub log_debug { log_message('DEBUG', @_) }
sub log_info { log_message('INFO', @_) }
sub log_warn { log_message('WARN', @_) }
sub log_error { log_message('ERROR', @_) }
log_debug("Debugging information");
log_info("Processing started");
log_warn("Low disk space");
log_error("Failed to connect");调试技巧
使用 warn 进行调试
perl
sub process_data {
my ($data) = @_;
warn "Processing data: $data\n";
# ... 处理代码 ...
warn "Data processed successfully\n";
}使用 Data::Dumper
perl
use Data::Dumper;
my $complex_data = {
users => [
{name => "Alice", age => 25},
{name => "Bob", age => 30}
]
};
# 打印数据结构
warn Dumper($complex_data);使用 Carp
perl
use Carp;
# cluck - 带堆栈跟踪的警告
sub check_value {
my ($value) = @_;
cluck "Value is negative" if $value < 0;
}
# confess - 带堆栈跟踪的致命错误
sub critical_error {
confess "Critical error occurred";
}
# carp - 调用者级别的警告
sub process {
carp "Processing warning";
}实践示例
示例 1:带错误处理的文件操作
perl
#!/usr/bin/perl
use strict;
use warnings;
use Try::Tiny;
sub read_file_safely {
my ($filename) = @_;
try {
open(my $fh, '<', $filename) or die "Cannot open $filename: $!";
my @lines = <$fh>;
close($fh);
return \@lines;
}
catch {
my $error = shift;
warn "Error reading file: $error";
return undef;
};
}
my $file = 'data.txt';
my $content = read_file_safely($file);
if ($content) {
print "File read successfully\n";
print @$content;
} else {
print "Failed to read file\n";
}示例 2:数据库错误处理
perl
#!/usr/bin/perl
use strict;
use warnings;
use DBI;
use Try::Tiny;
sub connect_to_database {
my ($dsn, $user, $password) = @_;
try {
my $dbh = DBI->connect($dsn, $user, $password, {
RaiseError => 1,
PrintError => 0,
AutoCommit => 0
});
return $dbh;
}
catch {
my $error = shift;
die "Database connection failed: $error";
};
}
sub execute_query {
my ($dbh, $query, @params) = @_;
try {
my $sth = $dbh->prepare($query);
$sth->execute(@params);
return $sth->fetchall_arrayref({});
}
catch {
my $error = shift;
$dbh->rollback;
die "Query failed: $error";
};
}
# 使用
my $dbh = connect_to_database(
'DBI:mysql:database=test;host=localhost',
'user',
'password'
);
my $results = execute_query($dbh, 'SELECT * FROM users');
print Dumper($results);
$dbh->disconnect;示例 3:Web 服务错误处理
perl
#!/usr/bin/perl
use strict;
use warnings;
use LWP::UserAgent;
use Try::Tiny;
use JSON;
sub fetch_url {
my ($url) = @_;
try {
my $ua = LWP::UserAgent->new();
$ua->timeout(10);
my $response = $ua->get($url);
unless ($response->is_success) {
die "HTTP request failed: " . $response->status_line;
}
my $data = decode_json($response->content);
return $data;
}
catch {
my $error = shift;
warn "Error fetching URL: $error";
return undef;
};
}
my $api_url = 'https://api.example.com/data';
my $api_data = fetch_url($api_url);
if ($api_data) {
print "API request successful\n";
print Dumper($api_data);
} else {
print "API request failed\n";
}小结
本章节学习了 Perl 的错误处理:
- ✅ die 和 warn
- ✅ eval 错误捕获
- ✅ 自定义错误处理
- ✅ Try::Tiny 模块
- ✅ 异常类
- ✅ 日志记录
- ✅ 调试技巧
接下来,我们将学习 Perl 特殊变量。