MENU

从一段烂代码中总结编码习惯

August 10, 2013 • 程序阅读设置

首先我先承认标题确实是缩减了,原意是“从一段别人七拼八凑的烂代码中总结自己优良的编码习惯”。(自恋了)自己感觉最近也确实没做什么技术性的东西,不写点儿原创的这个月就过去了,那就拿来别人的东西说事儿吧。事情是这样的,前几天某位找我说一个注册部分重写了显示层后逻辑业务工作不正常了,让帮忙看看。看看就看看吧,一看,嗬,问题真不少。

这段代码的作者是php初学者,写得不好也是无可厚非。我可以确定的是他的这个简易系统一定是拿别人的实例改的,数据库里有很多奇怪的字段,整个逻辑业务部分变量命名复杂觉历。当然这不是问题,谁不是从改实例做起的呢?好了,废话不多说,下面我们就一起自上而下地通篇看一看(个人拙见,不喜轻拍)。

1.对用户的输入一定要进行严格的审查,但是不能乱来。
众所周知,web应用的安全是非常重要,程序猿在任何时候都必须要对用户的输入保持警惕。我们要树立一个概念就是所有用户输入都必须假定它是dirty的,一定要进行过滤。用户的输入有很多种类型,很常见的比如用户名,密码,输入的一些文字等,都是有其规则的。我们来看看这段代码是怎么做的。打开整个文件,php块映入眼帘的第一句话就是preg_match_all('([0-9]+)',$_GET['m_pw'], $liujie_pssk);,后面还写着几个字的注释“正则转换”。相信这很容易明白,被过滤的字段是密码。注册页面有明确要求密码需要是纯数字。很明显,这句话执行完毕后$liujie_pssk变量就会变成符合正则规则的数组。这里我就不明白了,程序接下来的处理均使用$liujie_pssk,你这样过滤有何意义呢?如果用户输入含有其他成分岂不就是改变了原来的密码吗?真的需要用正则的话,不也是应该把preg_match_all放在if中去判断么?那么我们想想这里有没有比较便捷一点的方法呢?答案是肯定的。因为php有自动类型推算,这里仅需要这样就可以搞定:if(!is_numeric($_GET['m_pw'])){/*异常处理*/exit;}就完事儿了。

2.判断的条件简明点儿,别让自己闹不明白。
初步判断了密码之后,接下来就是对密码位数进行验证了。系统的要求是密码位数不得小于6位、不得大于24位。那么这位朋友是怎么解决这个问题的呢?首先,他写了$passzy=strlen($liujie_pssk[0][0]);,这好理解,$passzy在执行完毕后就是用“传说中的”“正则转换”得到的全部内容的第一条的位数了。接着出现了"if (($passzy-6)<0)就异常"这种匪夷所思的写法。这我是真心不明白啊,if($passzy<6)多简单啊。

3.把简单的活儿放到最开始去干。
前边儿扯了这么多,接着往后边看看到的是大段的判断。判断什么呢?用户输入。这部分的判断是判断该填的地方用户是不是真填了(大白话,其实就是检查是否为空)。到了这里,程序设计的不合理性就体现出来了。你前边儿费这么大功夫整那密码,结果这里别人玩儿你没填,前边不就是白忙活了吗?所以,这些还是放到最开始去做吧!少做一点功,给你的服务器减负,速度也能快点儿(即使是微不足道的无法感知的时间)。

4.请善待php最好的小伙伴——MySQL。
玩儿php的都知道,php是"dirty but quick"的开发语言。为啥quick呢?这与数据库不无关系。很多工作都是数据库直接完成了,着实十分简便。通常来说为了简便操作,我们有一定的几率会使用数据库封装。面向对象的封装类使用起来那叫一个舒服,但是如此使用长久了,可能会造成一些麻烦:直接用php写SQL语句会有困难,小错误不停地犯。拿我自己来说,之前因为SQL语句问题和Hans一起折腾了至少半个小时,最终发现是一个单引号位置不对。我们来看看这位朋友是怎么处理他的数据库操作的。

require_once ('inc.php');
$_SESSION['pass']="ok";
$_SESSION['member']=$_GET['m_acct'];
$link = getDBLink();
$ccbbaa='1';
$sql="insert into member values('".$_GET['m_acct']."','".$_GET['m_pw']."','".$_GET['m_name']."','','','".$ccbbaa."','')";
$result=mysql_query($sql)or die(mysql_error());
if($result>0)
echo "". $_GET['m_acct'].",恭喜你注册成功,<a href='20.php'>马上激活帐号...</p>";
else
{
    $_SESSION['pass']="no pass";
    echo "注册失败!<a href-'register.php'>重新注册。</a></p>";
    mysql_close();
}

很容易得知inc.php中含有数据库连接的部分,这里就不赘述了。接下来两个SESSION全局变量的操作很显然地是对下一步的操作,这里不讲,我们看的是数据库操作。$link=getDBLink();这里是非常没必要的,因为下面并没有判断数据库是否连接成功的内容,所以个人认为只需getDBLink();就好。接下来就是对SQL语句的说明了。MySQL中,关键字是大小写不敏感的,不过为了使整个语句看起来更加舒服,我通常会大写。接着,为了保证万无一失,数据表名、字段名最好是用反单引号包括起来。这个反单引号不是什么高级的玩意儿,就是切换到半角输入后再按你键盘上面那一横排数字,数字“1”左边的那个键得到的东西。也就是`。回到这位的SQL语句上来,可以看出他想偷懒。为什么呐?VALUES关键字前没有定义字段,反倒后边儿麻烦了。

至于他这里引号使用的问题,接着会提到的。至于or die(mysql_error());,是非常不合适的,我觉得没有哪位开发者想让最终用户看到错误信息。用户体验下去了是小事,万一(只是万一)谁根据这些信息黑进来了可怎么办呢!接着的语言结构错误就不提了,前边说过。我们看的是逻辑问题。if($result>0)感觉比较奇怪。在这里,INSERT操作如果查询成功返回true,失败返回false大家都知道的。的确true不严谨地说是在大于0这个范围内的,可是这么显然有着弊端。在这里是不是应该用if(!$result)呢?

5.快弄明白字符串中的单双引号区别并学会如何正确使用。
php中字符串需要用引号包含。通常来说,我会强烈推荐你使用单引号,如:$message='I love you.';。没错,单双引号可以用,但是它们也是有区别的。区别就在于php执行时会对双引号中的内容进行扫描,检查是否存在变量。如$name='Bokjan';$message="{$name}, I love you.";echo $message;输出的结果就是Bokjan, I love you.。这下应该很好明白为啥我推荐你一般情况下使用单引号了。省去了检查变量这一部分,肯定得快一些。当然双引号也是个好东西,在SQL语句中用到它就比你用单引号然后数次打断加入变量要方便的多了。为了使php检查变量更加方便快捷,也为了你的程序赏心悦目利于调试,在双引号中使用变量请把变量用花括号括起,就像上面一样。如果你真的要问“我真心要使用大括号在字符串里该怎么办”,那我也会告诉你(这应该不会有人问吧):转义!

6.正确转义字符及合理地输出html代码。
接着刚才的话题,我们谈到了转义。首先我想说到的就是我建议html中用到的引号全部都使用双引号,即使你用单引号浏览器也可以解析。这随之而来就会出现问题,如果在用了双引号的字符串里放上html代码,那报错是必须的了。这时候怎么办?在你html的双引号前加上一个反斜杠!注意了,反斜杠是"\"而不是"/","/"叫斜杠。转义,顾名思义,转换意义。加上反斜杠后那个双引号就会变成字符串而不会解释成php的语言结构一部分了。关于第5点提到的花括号,也在前面加上一个反斜杠就好。

到这里这位朋友写的代码就结束了,不过,我还有点话想说……

7.在面向过程编程中加入点儿函数会增长寿命。
php应该是为数不多的POP(Procedure Oriented Programming)也成O(Object)OP也成的语言。个人是极不赞成滥用面向对象的,在这里面向过程不失为一个好方法。然而他写的代码中有很多抛出异常部分,却都是纯手写的,看着都心疼。累啊!我衷心地建议可以把这一部分写成一个函数,用的时候调用吧。想想,是exit( "UID不能为空!<a href='register.php?m_name=".$_GET['m_name']."'>返回重新注册。</a></p>");方便还是showError('uid');方便呢。

8.我最后扯一点,关于打印。
大家知道,要打印内容有三种很常用的方法:printechoprint_rprint_r是用来打印复合类型的数据的,如数组、对象。而printecho用来输出字符串。众所周知的说法是print是一个函数而echo只是语言结构。print有返回值,所以仅仅只是输出的话咱应该用echo,速度快嘛。看起来事实上的确是这样。然而echo是一种特殊的语言结构,咱可以“把它近似地当作函数”使用。还是举一个例子:$name='Bokjan';echo $name.', I love you.';。这应该是普遍所采用的方法。因为大家都知道连接符是句点.。刚才提到了可以“近似地当作函数”使用又是怎么回事儿?还是来一个例子吧:$name='Bokjan';echo $name,', I love you.';。我可以担保这句输出和上句内容完全相同。函数参数之间不就是用逗号分隔的么?也许你想问“为啥这样做”,这个道理很简单:因为它更快。

Archives Tip
QR Code for this page
Tipping QR Code