perl编程规范
1?命名规则1.1?文件命名文件名称统一用英文字母(大小写)、数字和下划线的组合,长度一般不超过20个字符,文件命名体现功能的含义,正式发布版本不能加入作者信息。Perl?Scripts?文件的扩展名必须是".pl",Perl?Module文件的扩展名必须是".pm"。 正确: lucent_file_parser.pl 不是: lucent_file.p 1.2?标识符?采用语法模板来定义标识符的名字,命名必须有一定的实际意义,由英文字母组成,中间可以根据语义的连续性,使用下划线连接。 1.2.1?变量局部变量必须由小写字母和下划线组成,常量名必须由大写字母和下划线组成。由多个单词组成的名字里,使用下划线"_"把多个单词分开。全局变量以’g_开头,其余部分的命名规则和局部变量相同。每个全局变量必须有注释说明其作用。 正确: my?$next_node;?????????????? 不是: my?$node; 1.2.2?包和类包、类的命名采用大小写混合、首字母大写的方法。 正确: IO::Controller 1.2.3?标识符缩写标识符缩写时要保留单词的开始字母,不是辅音字母的简写。 正确: ????use?List::Util?qw(?max?); ????DESC: ????for?my?$desc?(@orig_strs)?{ ????????my?$len?=?length($desc); ????????next?DESC?if?($len?>?$UPPER_LIM); ????????$max_len?=?max($max_len,?$len); } 不是: ????use?List::Util?qw(?max?); ????DSCN: ????for?my?$dscn?(@rgnl_strgs)?{ ????????my?$lngh?=?length?$dscn; ????????next?DSCN?if?$lngh?>?$UPPR_LMT; ????????$mx_lngh?=?max($mx_lngh,?$lngh); ????} 1.2.4?函数由小写字母、下划线组成。 正确: sub?max { ???…… } sub?get_msc_name ??} 不是: sub?getMscName { ??…… } 1.3?布尔类型boolean类型的变量,或返回boolean类型的值的函数,在命名时要反映其属性,必须用is或者has开头。 正确: ????sub?is_valid; ????sub?is_metadata_available_for; ????sub?has_end_tag; ????my?$has_loading_finished; ????my?$has_found_bad_record; ????#?and?later... ????if?(is_valid($next_record)?&&?!$has_loading_finished)?{ ????????METADATA: ????????while?(is_metadata_available_for($next_record))?{ ????????????push?@metadata,?get_metadata_for($next_record); ????????????last?METADATA?if?(has_end_tag($next_record)); ????????} ????} ????else?{ ????????$has_found_bad_record?=?1; ????} 1.4?数组和哈希数组类型的变量采用复数,hash类型的变量采用单数。要用undef显式释放变量空间。 正确: ????my?%option; ????my?%title_of; ????my?%count_for; ????my?%is_available; ????if?($option{'count_all'}?&&?$title_of{$next_book}?=~?m/$target/xms)?{ ????????$count_for{$next_book}++; ????????$is_available{$next_book}?=?1; ????my?@events; ????my?@handlers; ????my?@unknowns; #?and?later... ????for?my?$event?(@events)?{ ????push?@unknowns,?grep?{?!?$_->handle($event)?}?@handlers; ????print?map?{?$_->err_msg?}?@unknowns; 2?注释所有注释可用英文或中文书写,尽量使用英文注释。保持注释和代码的完全一致,修改程序时,必须修改相应的注释。注释的行数一般应在程序总行数的1/5到1/3。禁止出现错别字。注释应该语义明确,避免出现二义性。 2.1?文件头部注释每个含有源代码的文件必须在文件开始有关于该文件的介绍性注释。其中列出文件名、创建者、创建日期、功能描述、版本信息、版权声明;如果对文件进行了修改,应该在文件头中说明修改人、修改日期、修改原因,并变更文件的版本信息,最新版本信息放到最前面。 格式为: #********************************************************* ?FileName:?lucent_file_parser.pl #?Creator:?Phonix?<phonix@gmail.com.cn> #?Create?Time:?2006-01-09 #?Description:?This?is?the?proof-of-concept?code?for?the #???????????Windows?denial-of-serice?attack?described?by #???????????the?Razor?team?(NTBugtraq,?19-May-00). CopyRight:?Copyright???Bright?Ocean?Inter-Telecomm,All?rights?reserved. Revision:?V1.0.0 #?ModifyList: ???Revision:?V1.1.1 ???Modifier:?Phonix? #???ModifyTime:?2006-0-17 #???ModifyReason:?fix?the?bug?of?# #???Revision:?V1.1.0 #???M:?Phonix 16 #???ModifyReason:?add?mysql&oracle?db?support #********************************************************* 不是简单的: #======================================== #Created?By:Phonix #Created?Time:??2006-01-09 #Modified?Time:?2006-01-17 #======================================== 2.2?文件中注释建议在文件中标识出修改部分的起止位置。 正确: ?add?mysql&oracle?db?support?begin ?end 2.3?函数注释在每个函数前必须写描述性注释。说明这个函数的功能、参数和函数的返回值。 格式为: #******************************************************************* ?Function?Name:?calc_time($datetime,?$delta) ?Description:?This?function?calculate?the?new?datetime.? #?Parameters: #???1.?$datetime?is?the?base?time,?taking?the?format?of?'yyyy-mm-dd?hh:mm:ss' #???2.?$delta?is?the?time?which?should?be?add?to?the$datetime.?A?positive?value?increase?the?time #??????while?the?negative?vale?decrease?the?time #?Return: #??????A?new?time?string?is?returned,?also?taking?the?format?of?'yyyy-mm-dd?hh:mm:ss'? #********************************************************************* 不是简单的: ########################################## #function?name?:?get_ldap #desc?:??get?config?info?from?ldap?server ########################################## 2.4?程序块注释程序块注释用于说明程序中的关键算法、使用某种技巧的代码以及修改、测试、阅读时必须加以注意的代码。 格式为: #********************************************************************* #注释内容 #...... #******************************************************************** 2.5?语句注释用于对特定程序语句进行说明,建议采取在语句行末尾说明的方法,同时注释换行后也要对齐。格式为: my?@names?=?( ????????'Damian',????#?Primary?key ???????????????????#?the?key?is? ????????'Matthew',???#?Disambiguator ????????'Conway',???#?General?class?or?category ????); 3?代码布局3.1?括号建议括号、插入语可以采用两种方式之一,但是在一个程序里选定那种方式之后,那么要至始至终保持一致。 3.1.1?方式一采用K&R风格。 格式为: ????my?@names?=?( ????); ????for?my?$name?(@names)?{ ????????for?my?$word?(?anagrams_of(lc?$name)?)?{ ????????????print?"$wordn"; ????} 3.1.2?方式二括号对{}对必须位于同一列,独占一行,并且和{}之外的语句行对齐 ????my?@names?= ????(
#?General?class?or?category ????for?my?$name?(@names) ????{ ????????for?my?$word?(anagrams_of(lc?$name)) ????????{ ????} 3.2?关键字把关键字和其他的内容分开,关键字if,?while,?for,else…后面必须接一个空格。if和while语句必须使用’{‘和’}’括起语句体,即使只有一行代码。建议不使用单行的if语句。 正确: for?my?$result?(@results)?{ ????????print_sep(?); ????????print?$result; ????while?($min?<?$max)?{ ????????my?$try?=?($max?-?$min)?/?2; ????????if?($value[$try]?<?$target)?{ ????????????$max?=?$try; ????????else?{ ????????????$min?=?$try; if?($condition){ i++; } 不是: ????for(@results)?{ ????????print_sep(?); ????????print; ????} ????while($min?<?$max)?{ ????????my?$try?=?($max?-?$min)?/?2; ????????if($value[$try]?<?$target)?{ ????????????$max?=?$try; ????????} ????????else{ ????????????$min?=?$try; ????????} } if($condition)?{$i++;} 3.3?子程序和变量不要把子程序或变量和其后的括号部分分开。 正确: my?@candidates?=?get_candidates($marker); ????CANDIDATE: ????for?my?$i?(0..$#candidates)?{ ????????next?CANDIDATE?if?open_region($i); ????????$candidates[$i] ????????????=?$incumbent{?$candidates[$i]{region}?}; ????} 不是: ????my?@candidates?=?get_candidates?($marker); ????CANDIDATE: ????for?my?$i?(0..$#candidates)?{ ????????next?CANDIDATE?if?open_region?($i); ????????$candidates?[$i] ????????????=?$incumbent?{$candidates?[$i]?{region}}; ????} 3.4?代码缩排缩进采用四个空格,或一个TAB(1?TAB?设置成四个空格)。 3.5?代码块不要把两句话放在一行,每行只能写一个语句。 正确: while?(my?$record?=?<$inventory_file>)?{ chomp?$record; next?RECORD?if?$record?eq?$EMPTY_STR; my?@fields?=?split?$FIELD_SEPARATOR,?$record; update_sales(@fields); $count++; } 不是: ????while?(my?$record?=?<$inventory_file>)?{ ????????chomp?$record;?next?RECORD?if?$record?eq?$EMPTY_STR; ????????my?@fields?=?split?$FIELD_SEPARATOR,?$record;?update_sales(@fields);$count++; ????} 3.6?代码长度每个函数体的语句行不能超过100行(不包括注释,一个分号算一行)。每行长度不要超过78个字符,超过该长度时,必须考虑换行,从低优先级的操作符处分割长表达式,?在赋值符前断开长的语句。 正确: push?(@steps,?$steps[-1] ?????????????????+?$radial_velocity?*?$elapsed_time ?????????????????+?$orbital_velocity?*?($phase?+?$phase_shift) ?????????????????-?$DRAG_COEFF?*?$altitude); $predicted_val?=?$average?+?$predicted_change?*?$fudge_factor; 不是: push?(@steps,?$steps[-1]?+?$radial_velocity ?????????????????*?$elapsed_time?+?$orbital_velocity ?????????????????*?($phase?+?$phase_shift)?-?$DRAG_COEFF ?????????????????*?$altitude); $predicted_val?=?$average ?????????????????????+?$predicted_change?*?$fudge_factor; 3.7?操作符二元运算符(算术运算符,?赋值运算符等)的两边都要接空格,低级操作符(如:+-)两边各有两个空格,高级操作符(如:*%)两边各有一个空格。 在运算符'->'两边不要使用空格,在一元操作符和操作数两边不要使用空格。 可以使用括号来表示运算的先后顺序。 正确: my?$displacement ????????=?$initial_velocity?*?$time??+??0.5?*?$acceleration?*?$time**2; my?$price ????????=?$coupon_paid?*?$exp_rate??+??($face_val?+?$coupon_paid)?*?$exp_rate**2; 不是: my?$displacement=$initial_velocity*$time+0.5*$acceleration*$time**2; my?$price=$coupon_paid*$exp_rate+(($face_val+$coupon_val)*$exp_rate**2); 3.8?语句结束符在每个语句后边要填加分号。 正确: while?(my?$line?=?<>)?{ ????????chomp?$line; ????????if?(?$line?=~?s{A?(s*)?--?(.*)}{$1#$2}xms?)?{ ????????????push?@comments,?$2; ????????print?$line????} 3.9?代码排列数组或Hash的赋值采用垂直排列。 正确: my?@months?=?qw( ????????January???February???March ????????April?????May????????June ????????July??????August?????September ????????October???November???December ????my?%expansion_of?=?( ????????q{it's}????=>?q{it?is}, ????????q{we're}???=>?q{we?are},0)">????????q{didn't}??=>?q{did?not},0)">????????q{must've}?=>?q{must?have},0)">????????q{I'll}????=>?q{I?will},0)">????); ???? 不是: ????my?@months?=?qw( ????????January?February?March?April?May?June?July?August?September ????????October?November?December ????); ????my?%expansion_of?=?( ????????q{it's}?=>?q{it?is},?q{we're}?=>?q{we?are},?q{didn't}?=>?q{did?not}, ????????q{must've}?=>?q{must?have},?q{I'll}?=>?q{I?will},240)">????); 3.10?非末端表达式采用中间变量代替长表达式。 正确: my?$next_step?=?$steps[-1] ????????????????????+?$radial_velocity?*?$elapsed_time ????????????????????+?$orbital_velocity?*?($phase?+?$phase_shift) ????????????????????-?$DRAG_COEFF?*?$altitude ????????????????????; ????add_step(?@steps,?????add_step(?@steps,?$steps[-1] ???????????????????????+?$radial_velocity?*?$elapsed_time ???????????????????????+?$orbital_velocity?*?($phase?+?$phase_shift) ???????????????????????-?$DRAG_COEFF?*?$altitude ???????????????????????,?$elapsed_time); 3.11?功能块顺序在每个Perl?Scripts中,每个功能块之间必须有一个空行。主程序为main()函数,功能块出现顺序如下: use?modules; global?variable?定义 main定义 subroutine?定义 4?数值和表达式4.1?字符串界定符需要用变量替换的字符串用双引号,否则用单引号。 正确: my?$spam_name?=?"$title?$first_name?$surname"; my?$pay_rate??=?"$minimal?for?maximal?work"; my?$spam_name?=?'Dr?Lawrence?Mwalle'; my?$pay_rate??=?'$minimal?for?maximal?work'; 4.2?常量使用字符常量,而不要直接用数值。 正确: use?Readonly; ????Readonly?my?$MOLYBDENUM_ATOMIC_NUMBER?=>?42; print?$count?*?$MOLYBDENUM_ATOMIC_NUMBER; 不是: print?$count?*?42; 4.3?字符串4.3.1?两行对于两行的字符串,要用“.”进行连接。 正确: $usage?=?"Usage:?$0?<file>?[-full]n" .?"(Use?-full?option?for?full?dump)n"; 不是: ?$usage?=?"Usage:?$0?<file>?[-full] (Use?-full?option?for?full?dump)"; 4.3.2?多于两行对于多于两行,要采用如下格式: 正确: ????$usage?=?<<"END_USAGE"; ????Usage:?$0?<file>?[-full]?[-o]?[-beans] ????Options: ????????-full??:?produce?a?full?dump ????????-o?????:?dump?in?octal ????????-beans?:?source?is?Java END_USAGE 不是: ????$usage?=?"Usage:?$0?<file>?[-full]?[-o]?[-beans]n" ?????????????.?"Options:n" ?????????????.?"????-full??:?produce?a?full?dumpn" ?????????????.?"????-o?????:?dump?in?octaln" ?????????????.?"????-beans?:?source?is?Javan" ?????????????; 4.4?哈希变量Hash变量的定义采用双箭头(=>)方式。 正确: ????%default_service_record??=?( ????????name=>?'<unknown>',0)">????????rank=>?'Recruit',0)">????????serial=>?undef,0)">????????unit=>?['Training?platoon'],0)">????????duty=>?['Basic?training'],0)">????); 不是: ????%default_service_record??=?( ????????'name',???'<unknown>',240)">????????'rank',???'Recruit',240)">????????'serial',?undef,240)">????????'unit',???['Training?platoon'],240)">????????'duty',???['Basic?training'],240)">????); 5?函数5.1?调用语法调用时要使用圆括号,不管是否有参数。 正确: fix(); coerce($input,?$INTEGER,?$ROUND_ZERO); 不是: fix; 5.2?函数返回在函数中要进行显式的return返回。 正确: ????sub?set_terseness?{ ????????my?($terseness)?=?@_; ????????my?$default_terseness?=?$terseness; ????????return;??#?Explicitly?return?nothing?meaningful } 不是: ????sub?set_terseness?{ ????????my?($terseness)?=?@_; ????????my?$default_terseness?=?$terseness; ????} 6?编程惯例6.1?使用use?strict所有Perl?Scripts?文件中必须在开始使用“use?strict;”,进行严格的语法检查,便于查找错误。 6.2?避免使用内部变量名称避免使用Perl内部变量。使用“use?English;”装入Perl内部变量的符号名称。使用my来限定变量的作用域。下面是一些Perl内部变量名称的对应关系。 ??????$_??????$ARG ??????@_?????@ARG ??????$!??????$ERRNO ??????$???????$CHILD_ERROR ??????$$??????$PID ??????$0??????$PROGRAM_NAME ??????$.??????$INPUT_LINE_NUMBER ??????$|??????$OUTPUT_AUTOFLUSH ??????$@?????$EVEL_ERROR ??????$&?????$MATCH ??????$`??????$PREMATCH ??????$'??????$POSTMATCH ??????$+?????$LAST_PAREN_MATCH ??????$/??????$RS ??????$??????$ORS ??????$<?????$UID ??????$>?????$EUID ??????$(??????$GID ??????$)??????$EGID ??????$]??????$PERL_VERSION ??????$???????$CHILD_ERROR 6.3?避免使用goto避免使用goto语句(只有在从多重循环的内部跳出时才可以使用)。除非能够特别有效的增加程序的效率并且不影响程序良好结构的特殊情况。 6.4?语法检查(辅助工具)使用-cw选项检查Perl程序的语法。 正确: perl?-cw?-Mdiagnostics?file.pl?????????????#?check?syntax?with?warnings?on nt;???????#?Perl?5.004_04,?define?constants use?Env;??????????#?instead?of?$ENV{'HOME'};?Shortens?the?usage,?but?do?not? #?mix?normal?variables? ???????????????????????#?with?environment?variables. 6.5?use?Carp;??????????#?For?modules:?使用标准模块尽量使用标准库函数、公共函数和开发库中已有的函数和模块,使用FileHandle模块来处理文件的读写。尽量使用以下的标准Perl模块: use?strict;?????????#?helps?you?to?locate?syntax?errors?or?uncertainties. use?integer;????????#?if?you?don't?need?floating?point?math,it?will?speed?Perl?up. use?constagives?you?`carp'?and?`croak' use?English;????????#?gives?symbolic?names,?like?$!?==>?$ERRNO use?Getopt::Long;???#?--posix?command?line?option?handling use?Cwd;???????????#?platform?independent?cwd() use?File::Basename;??#?don't?invent?your?own?wheel?of?this. use?File::Find;???????#?don't?use?system("find?.?-name?...")... use?File::copy;??????#?don't?use?system("cp?this?that"); use?File::patch;??????#?instead?of?system("mkdir"); use?File::stat;???????#?readable:?$st?=?stat($file),?$st->mode use?DirHandle;??????#?OO?form?of?`readdir' use?Text::Tabs???????#?un/expand?tabs?in?text use?Text::ParseWords;?#?Parse?text?into?tokens,?understands?embedded ?????????????????????????#?quotes.?@a?=?"ewords("[?+]",?0,?$_); ?????????????????????????#?a+b,?"a?b"?+?c use?Socket;?????????#?socket?handling use?Sys::Hostname;??#?don't?invent?your?own?wheel use?Net::Ping???????#?unix?ping,?check?if?host?is?online use?Time::Local?????#?time?manipulations 6.6?其他1、编码、测试、注释,是程序员的三项基本工作,它们是同等重要的。 2、可靠性第一,可读性第二,效率第三。只有在极个别必须强调效率的部分,可以是可靠性第一,效率第二,可读性第三。 3、首先是正确,其次是优美。 4、无法证明你的程序没有错误。因此,在新编写完一段程序后,应该测试通过后再继续编码。 5、改正一个错误的同时,可能会引起新的错误。因此,在修改bug前,首先考虑对其他程序的影响。修改后,应该对程序进行完整的测试,而不是只对修改部分进行测试。 6、避免使用很多个参数的函数。 7、函数应该只有一个出口。 8、循环应该只有一个出口,避免多个出口。 9、尽量避免使用全局变量。 10、在尽可能小的作用域内定义和使用变量。 11、使用括号,表达复杂表达式中的操作符的优先顺序。 12、循环、分支不要超过五个层次。 13、循环、分支等语句后,即使只有一行代码时,也要使用{}将其括起来。 14、禁止else?goto和else?return。 15、重复使用的、完成相对独立功能的算法、代码,应该抽象为公共模块。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |