Tips and Style of My PHP Codeing.
作者:罗文辰
这篇文章著重在‘方法论’而不是实作上的技术,所以这篇文章并不会教导您任何实作上的
技巧和实例。如果您是个只问结果不看过程的人,请您不要浪费时间来看这篇文章。
*** 关于 PHP 与网页程式设计 ***
PHP 是一种很强大又方便的工具,她能够让一般对程式设计不是很瞭解的人写出一般网路
的应用程式,并允许您在撰写 PHP 的程式时不需要做太多的规划与文件准备。特别是如果
您本身已经对 C/C++、Perl、Java 有一定的程度时,您几乎不必任何的学习就能写出很像
样的程式。
很不幸的,这就像一把剑的两面,有利有弊,您很容易写出松散、没有结构、不易维护的程
式,我非常的清楚这一点,因为我写过太多类似的 PHP 程式。这类的程式有一个称呼:
Quick and Dirty (快与杂乱)。
也许您已经开始了一个或数个不错的计划,并尝试著为该计划撰写一些像样的程式,也许您
正在思考著找一个架构更好的语言来取代 PHP (如 JSP),但其实您应该知道,一个程式的
好坏是决定在程式员而不是所使用的语言,这就像是武侠小说中讲的心中有剑意,花草皆为
剑的道理是不谋而合的,其实用什么语言不是重点,这篇文章也和 PHP 没什么关系,我只
是以 PHP 来当范例说明一些观念罢了。
我并不是很清楚高手们认为一个好的程式原始码要有什么条件,但我认为一个好的程式大致
上一定要有:
1.变数命名清楚
2.结构控制良好
3.容易阅读
4.注解与文件说明详细
5.错误与例外处理完善
以下我要说的技巧其实是通用于任何高阶的程式语言,只是拿 PHP 来当范例而已。
*** 缩排的技巧 ***
有写过程式的人都会知道,缩排 (Indenting) 是写程式的基本风格与技巧之一,缩排能让
您的程式容易阅读与维护,而缩排的间隔究竟要多少才恰当,我知道有许多人都是使用 TAB
来做他们的缩排的,而有看过我程式的人都很清楚我一直都是用四个空白字元来做缩排,主
要是因为不喜欢 TAB 一次跳八个空白让我的程式被拖得很长才这样用的,但后来看到有许
多高手也都建议您使用四个空白来当定格,(您可以在 C 语言的风格与艺术这本书看到相同
的说法,但我是在看过这本书之前就一直用四个空白来当 TAB 了)当然您也可以使用 TAB
来做缩排,我知道有些人是设定他的 editor 使 TAB 一次显示四个空白间隔而不是八个,
至于我自己是用‘真正的四个空白字元’来取代 TAB 字元的,这是为了让一些Viewer 看到
的缩排方式会完全相同。缺点大概就是占用了比较多的磁碟空间,产生出来的
Source Code File 会比较大,以大多数的 editors 来说,都可以让您自由设定 TAB,
像 UltraEditor, PE2/HE 等等。
结论:四个空白的缩排往往比八个空白(TAB预设值)的缩排好
*** 变数命名规则 ***
关于变数的命名一向是国内程式员很少去探讨的主题,其实命名是一种学问,最出名的就像
是MicroSoft 的匈牙利式命名法,所谓的匈牙利式命名法就是在变数名称前加上型别分辨的
方式,像:
$cMyChar = "c"; $sMyString = "this is a string"; $iMyInt = 2002; |
除此之外,还有一些约定成俗的习惯,最常见的像 Class 的命名方式,如 Class 的第一个
字母为大写,其他小写,字与字之间是以大小写来区分,而 Methods 的第一个字母为小写
,其他的同 Class,另外也有人会在 Class 之前加上大写 C 表示为 C Language 或
Class,像:
Class CMyClass { // 这个 C 有人说是 Class 有人说是 C Language 所以你会看到有些 Java Swing 的 Class 为了和 AWT 同名 Class 做区分会加 J: Class JButton { // 这个 J 就是 Java 啦 |
至于变数的命名除了匈牙利式命名,我们在最常看到的是 Unix 里典型命名法 => 加底线,
像:
$my_baby = "baby"; $whos_your_daddy = "not me"; |
不过也有人喜欢用大小写区分的方式像:
$myBaby = "baby"; $whosYourDaddy = "not me"; |
至于我见过另一种是完全连在一起写不分大小的,你可以在 VBD Forum 的 Source 中看到
这种命名法。
变数的命名其实是很自由的,所有的规则只是为了让整个开发团队中有个准则而已。
如果您的计划是由很多人一起写的,请试著建立共识,采用一定的撰码与命名标准想必可以
提升不少的效率。
试著先看一下这个程式:
$s = round($this->ey / $this->ln); |
我很不欣赏这样的写法,道理很简单,谁知道您的 $s、$ps、$ey、$sy 代表了什么,
更糟糕的是经过三个月之后,您想要替您自己的程式修改功能时,您才发现完了,因为您
根本已经忘记那些变数是干嘛用的,所以我宁愿用一些看起来很累赘的命名方式像
$step_value、$start_y 之类的变数名,这样我可以一看就很容易回想起来 $step_value
是用来代表间隔与间隔间的数值、$start_y 是用来代表起始的 Y 座标。这一点能确保我不
易忘记这个程式段是用来做什么用途的。
再看另一只其实是做同一件事的程式码:
$step = round($this->end_y / $this->line_num); // 计算每条线的间距 $i = 0; ImageLine($this->im, $this->start_x+$poly_size, $line_y, $line_y = $line_y - $step; |
是不是容易阅读多了?
其实每个人心目中都有个标准,函式与变数命名其实是很自由化的,要如何做是您自己的选
择,我不能保证我的方式是最好的,只是提供自己的心得,我的变(常)数命名原则就是:
最笨的方法往往都是最有用的方法。
*** 注解与说明文件 ***
适当的为您程式加上注解,可以让您或您的同事将来维护程式时事半功倍,当然如果这个程
式不小心外流了,那也很容易让别人搞清楚一些功能是怎么写的。注解用自己熟悉与瞭解的
语言就可以了,不一定要用英文,除非您的专案是要和一些老外合作的,
PHP 支援了 C Language 型态和 Shell Script 型态的注解方式,讲到 C 型态的注解我想
大家应该都很熟,不过说明文件在 PHP 中没有一个像 JavaDOC 那样有力的机制,所以我建
议是先把注解做好就好。
在 PHP 中的注解方式与 C 很类似:
您可以用 /* 和 */ 将您的注解包起来:
/*
这是 PHP 的注解
*/
也可以用 // 代表注解到行尾:
echo "Hello World!/n"; // 从这开始是 PHP 的注解。
echo "This is PHP Sample";
另一种方式是像 Shell Scripts 的 # ,作用和 // 一样是注解到行尾:
## 我也是注解
还有一些人或语言喜欢做一些变化像:
/*
* 我是猪头
* 我是一个大猪头
*/
/******************************************
* 这个程式是由猪头撰写,版权所有翻考必究 *
******************************************/
虽然看起来很猪头但不可否认的有招牌的效果
*** 结构控制 ***
所谓的结构控制就是 if, for, while 等条件判断与回圈的规则,有些人会说连这种东
西都要探讨规则那是不是太无聊了,其实这一点也不无聊,如果您有使用过 Unix 下的
一套叫 indent 的程式,光看那些复杂的参数您就会知道这一点都不简单,大体上来说
以 C 的结构来讲分为两大派,一派是 C 创始者 (K&R) 所使用的写法,另一派则是 GNU
的写法,而我个人是比较偏好 K&R 的写法,所以也在此仅以 K&R 的方式当范本:
您可能知道像一些 if 的控制式是这样写:
if ($hit_point <= $damage) echo "you are dead"; |
阅读性变差,甚至会搞不清楚这个 else 该和哪个 if 配对,像:
if ($a > $b ) $c = true; |
C 的老手应该会很清楚 else 是和最靠近的那个 if 配对,可是如果程式码不是短短四行而
是数千行时,这样的写法就会像是一颗颗的地雷不知何时会引爆。
因此不管要判断的东西是多么的简单,都应该要加上 {},像:
if ($hit_point <= $damage) { |
照这样来看,另一个范例我的建议写法会成为:
if ($a > $b) { |
可是这个程式看起来很糟糕对不对?
其实程式设计上有一个很重要的技巧和观念就是:不要把 if 写太多层的巢状,
所以上式应该改成更单层的写法:
if ($a > $b) { |
是不是好多了?
至于有另一种所谓的单行条件式像是:
// 这是错误的示范,请看接下来的说明
($hit_point <= $damage) ? echo "you are dead" : echo "you are alive"; |
以程式简洁的立场来说我不反对使用单行条件式,但是单行条件式在使用上需要小心,
一般来说我建议是在需要有赋值(assign value)动作时才用单行条件式,像:
$alive = ($hit_point <= $damage) ? false : true; |
因为在需要赋值时,使用 if 并不会占到多少便宜,像上式改用 if 来写就成为:
if ($hit_point <= $damage) { $alive = false; } else { $alive = true; // 做了两次赋值的动作,感觉起来似乎就笨多了。 } |
还有一个蛮好用的地方就是在于 function 中的返回值,像:
function myFunction($guess_num) { |
使用单行的判断式会有意想不到的方便:
function myFunction($guess_num) { return ($guess_num == $random_num)? true : false; } |
单行条件式纯脆是个人喜好,并没有好坏的问题,有些人极度反对单行条件式,我是觉得有
点追求架构到走火入魔的地步,个人是觉得该用的时候就用。
*** 后记 ***
在下才疏学浅,以上的心得只是在下的小小的经验累绩与自我遵行的规则,您不一定要按照
我的方式来写程式,因为在下很笨只能用这种方式来自我约束,我相信有许多天综英才的人
是不需要这样做的。
笔者最近公私上都发生很多事,所以都没稿件,觉得蛮对不起小企鹅的,因为原本 PHP 周
报是我提出来的想法,但发生了这些事也不是在下愿意的,而且自己其实懂得真的不多,实
在不敢野人献曝徒增笑柄,因此才一直强调所有的文章只是个人的小心得,不是什么了不起
的发现或研究成果。
此外好像有些人觉得笔者不是很喜欢发表一些应用上的技术,主要是因为那些东西在
php.net、RFC 或 PHP Builder里大都找得到,反而是方法与观念才是影响一个人学习成效
的最大关键。不过如果大家只喜欢吃牛肉面而不是想知道煮牛肉面的方法,我想我将来会提
供一些现成的牛肉面让大家吃吧,这可能是最后一篇讲观念的东西。