新浪微博 登陆  注册   设为首页 加入收藏

学PHP >> php开发经验 >> 20条常见的编码陷阱

20条常见的编码陷阱

查看次数20609 发表时间2012-11-24 00:36:15

转载于:http://www.csdn.net/article/2012-11-19/2811978-20-All-Too-Common-Coding-Pitfalls-For-Be

 

不管你现在的编程技能有多么的高超,曾经你也是个亦步亦趋,不断的学习的初学者。在编程这条曲折的道路上,我想你肯定犯过一些低级的错误、遇见过一些普通的编码陷阱。本文作者跨越多个语言,为大家总结了20条常规陷阱,并提供了解决方案。

JavaScript篇

1.不必要的DOM操作

例如下面这段代码:

  1. // anti-pattern  
  2. for (var i = 0; i < 100; i++){  
  3.    var li = $("<li>").html("This is list item #" + (i+1));  
  4.    $("#someUL").append(li);  

这段代码对DOM进行了100次修改,并且创建了100个不必要的jQuery对象。正确的做法是使用一个文档片段,或者创建一个字符串,把100个<li>元素赋给该字符串。然后附加到HTML中。这样就只需运行DOM一次,代码如下:

  1. var liststring = "";  
  2. for (var i = 100; i > 0; i--){  
  3.    liststring += "<li>This is list item #" + (99- i);  
  4. }  
  5. document.getElementById("someUL").innerHTML(liststring); 

正如上面所描述的一样,下面再提供一个方式,使用数组:

  1. var liststring = "<li>" 
  2. var lis = [];  
  3. for (var i = 100; i > 0; i--){  
  4.    lis.push("This is list item #" + (99- i));  
  5. }  
  6. liststring += lis.join("</li><li>") + "</li>";  
  7. document.getElementById("someUL").innerHTML(liststring); 

这是在JavaScript创建重复HTML最快最简单的方法,无需使用模板库或框架。

2.不一致的变量名和函数名

这个问题是非常重要的,尤其当你在别人的代码上工作时,一定要保持标识符(变量名和函数名)一致,例如下面这段代码:

  1. var foo = "bar";  
  2. var plant = "green";  
  3. var car = "red"

通常,人们并不会设置变量名叫Something,这涉及到命名规则问题,命名应清晰明了,一目了然。很多编程语言地变量命名都使用大写。

下面是对函数的命名:

  1. function subtractFive(number){  
  2.    return number - 5;  

语法结构清晰并且能起到解释性功能。

例如想要对给定的数字加5,仍采用上述命名模式,比如:

  1. function addFive(number){  
  2.    return number + 5;  

有时,你会根据返回值命名,例如该函数要返回一个HTML字符串,那么可以命名为getTweetHTML(),如果函数只是做一些操作,无需返回值,那么可以在前面加一个do前缀。例如doFetchTweets()。

构造函数通常会遵循类原则,大写第一个字母:

  1. function Dog(color){  
  2.    this.color = color;  

命名应带有描述性,比如操作型的函数在前面加do,另外要具备可读性和提示性。

3.在for...Loops中使用hasOwnProperty()方法

JavaScript数组是没有关联的,可以把它当做哈希表,使用循环来遍历对象属性:

  1. for (var prop in someObject) {  
  2.     alert(someObject[prop]); // alert's value of property  

然而,存在的问题是for...in loop是在对象属性链上遍历每个枚举类型的属性,如果你只想使用对象实际拥有的属性,这可能有问题的。那怎么解决呢?你可以使用hasOwnProperty()方法。代码如下:

  1. for (var prop in someObject) {  
  2.     if (someObject.hasOwnProperty(prop)) {  
  3.         alert(someObject[prop]); // alert's value of property  
  4.     }  

4.比较布尔值

把布尔值作为条件进行比较,其实这是在浪费电脑的计算时间。看下面这个例子吧:

  1. if (foo == true) {  
  2.     // do something for true  
  3. else {  
  4.     // do something for false  

其实foo==true这个比较完全是多余的,因为foo已经是布尔类型。直接这样写就行:

  1. if (foo) {  
  2.     // do something for true  
  3. else {  
  4.     // do something for false  

又或者这样写:

  1. if (!foo) {  
  2.     // do something if foo is false  
  3. else {  
  4.     // do something if foo is true  

5.事件绑定

在JavaScript中,事件是个复杂的问题。事件冒泡(event bubbling)和委托正在取代内联事件(inline onclick)操作(一些特殊的“初始页”除外)。

假设你有一个图片网格,需要启动一个modal lightbox窗口。千万不要采取下面的做法,示例采用的是jQuery,如果你使用相似的库或者其他,冒泡机制也同样适合传统的JavaScript。

相关的HTML代码:

  1. <div id="grid-container"> 
  2.    <a href="someimage.jpg"><img src="someimage-thumb.jpg"></a> 
  3.    <a href="someimage.jpg"><img src="someimage-thumb.jpg"></a> 
  4.    <a href="someimage.jpg"><img src="someimage-thumb.jpg"></a> 
  5.    ...  
  6. </div> 

不好的JavaScript写法:

  1. $('a').on('click'function() {  
  2.    callLightbox(this);  
  3. }); 

这段代码假设调用lightbox,里面传递一个anchor元素并且引用全屏图片。与其绑定每个anchor元素还不如直接使用#grid-container元素。

  1. $("#grid-container").on("click""a"function(event) {  
  2.    callLightbox(event.target);  
  3. }); 

在这段代码中,this和event.target都表示anchor元素。同样你也可以在任何父元素上使用。只要保证所定义的元素是事件目标就行(event's target)。

6.避免三元冗余

在JavaScript和PHP中,过度使用三元语句是很常见的事情:

  1. // javascript  
  2. return foo.toString() !== "" ? true : false
  1. // php  
  2. return (something()) ? true : false; 

条件判断的返回值永远只有false和true,言外之意就是你无需把true和false显示添加到三元运算中。相反,你只需简单的返回条件:

  1. // javascript  
  2. return foo.toString() !== ""
  1. // php  
  2. return something(); 

PHP篇

7.适当的时候使用三元操作

If...else语句是大多数语言的重要组成部分。但有些简单的事情,比如根据条件进行赋值,你很有可能会这样写:

  1. if ($greeting)  
  2. {  
  3.     $post->message = 'Hello';  
  4. }  
  5. else 
  6. {  
  7.     $post->message = 'Goodbye';  

其实使用三元操作只需一行代码就可以搞定,并保持了良好的可读性:

  1. $post->message = $greeting ? 'Hello' : 'Goodbye'

8.抛出异常,而不是采用盗梦空间式的嵌套(Inception-Style Nesting)

多层次的嵌套是丑陋的、难以维护和不可读的。下面的代码是个简单的例子,但是随着时间的推移会变得更糟:

  1. // anti-pattern  
  2. $error_message = null;  
  3. if ($this->form_validation->run())  
  4. {  
  5.    if ($this->upload->do_upload())  
  6.    {  
  7.       $image = $this->upload->get_info();  
  8.       if ( ! $this->image->create_thumbnail($image['file_name'], 300, 150))  
  9.       {  
  10.          $error_message = 'There was an error creating the thumbnail.';  
  11.       }  
  12.    }  
  13.    else 
  14.    {  
  15.       $error_message = 'There was an error uploading the image.';  
  16.    }  
  17. }  
  18. else 
  19. {  
  20.    $error_message = $this->form_validation->error_string();  
  21. }  
  22. // Show error messages  
  23. if ($error_message !== null)  
  24. {  
  25.    $this->load->view('form'array(  
  26.       'error' => $error_message,  
  27.    ));  
  28. }  
  29. // Save the page  
  30. else 
  31. {  
  32.    $some_data['image'] = $image['file_name'];  
  33.    $this->some_model->save($some_data);  

如此凌乱的代码,是否该整理下呢。建议大家使用异常这个清洁剂:

  1. try  
  2. {  
  3.    if ( ! $this->form_validation->run())  
  4.    {  
  5.       throw new Exception($this->form_validation->error_string());  
  6.    }  
  7.    if ( ! $this->upload->do_upload())  
  8.    {  
  9.       throw new Exception('There was an error uploading the image.');  
  10.    }  
  11.    $image = $this->upload->get_info();  
  12.    if ( ! $this->image->create_thumbnail($image['file_name'], 300, 150))  
  13.    {  
  14.       throw new Exception('There was an error creating the thumbnail.');  
  15.    }  
  16. }  
  17. // Show error messages  
  18. catch (Exception $e)  
  19. {  
  20.    $this->load->view('form'array(  
  21.       'error' => $e->getMessage(),  
  22.    ));  
  23.    // Stop method execution with return, or use exit  
  24.    return;  
  25. }  
  26. // Got this far, must not have any trouble  
  27. $some_data['image'] = $image['file_name'];  
  28. $this->some_model->save($some_data); 

虽然代码行数并未改变,但它拥有更好的可维护性和可读性。尽量保持代码简单。

9.False——Happy方法

Ruby或Python开发者常常关注一些微小的异常,这是相当不错的事情。如果有地方出错就会抛出异常并且你会立即知道问题所在。

在PHP中,特别是使用比较老的框架,如CodeIgniter,与抛出异常相比,它仅仅返回一个flase值,并且把错误字符串分配给其他一些属性。这就驱使你使用get_error()方法。

Exception-happy远远好于false-happy。如果代码里面存在错误(例如不能连上S3下载图片,或者值为空等),然后抛出一个异常,你也可以通过继承Exception类来抛出特定的异常类型,例如:

  1. class CustomException extends Exception {} 

抛出自定义类型异常会让调试变得更加容易。

10.Use Guard Clauses

使用if语句控制函数或方法的执行路径是很常见的事情,如果if条件为true就执行if里面的代码,否则就执行else里面的代码。例如下面这段代码:

  1. function someFunction($param) {  
  2.     if ($param == 'OK') {  
  3.        $this->doSomething();  
  4.        return true;  
  5.     } else {  
  6.        return false;  
  7.     }  

这是很常见的意大利面条式的代码,通过转换条件对上述代码进行优化,不仅可以增加其可读性,看起来还会更加简单,如下:

  1. function someFunction($param) {  
  2.     if ($param != 'OK'return false;  
  3.     $this->doSomething();  
  4.     return true;  

11.使用While进行简单的迭代

使用for进行循环是很常见的事情:

  1. for (var i = 0; i < x; i++) {  
  2.     ...  

当然,for循环也有许多优势,但是对于一些的循环,使用while或许会更好:

  1. var i = x;  
  2. while (i--) {  
  3.     ...  

12.保持方法可维护性

让我们来看一下这个方法:

  1. class SomeClass {  
  2.    function monsterMethod() {  
  3.       if($weArePilots) {  
  4.          $this->goAndDressUp();  
  5.          $this->washYourTeeth();  
  6.          $this->cleanYourWeapon();  
  7.          $this->takeYourHelmet();  
  8.          if($this->helmetDoesNotFit())  
  9.             $this->takeAHat();  
  10.          else 
  11.             $this->installHelmet();  
  12.          $this->chekcYourKnife();  
  13.          if($this->myAirplain() == "F22")  
  14.             $this->goToArmyAirport();  
  15.          else 
  16.             $this->goToCivilianAirport();  
  17.          $this->aim();  
  18.          $this->prepare();  
  19.          $this->fire();  
  20.       }  
  21.    }  

再看如下代码:

  1. class SomeClass {  
  2.    function monsterMethod() {  
  3.       if($weArePilots) {  
  4.          $this->prepareYourself();  
  5.          $this->tryHelmet();  
  6.          $this->findYourAirport();  
  7.          $this->fightEnemy();  
  8.       }  
  9.    }  
  10.    private function prepareYourself() {  
  11.       $this->goAndDressUp();  
  12.       $this->washYourTeeth();  
  13.       $this->cleanYourWeapon();  
  14.       $this->chekcYourKnife();  
  15.    }  
  16.    private function tryHelmet() {  
  17.       $this->takeYourHelmet();  
  18.       if($this->helmetDoesNotFit())  
  19.          $this->takeAHat();  
  20.       else 
  21.          $this->installHelmet();  
  22.    }  
  23.    private function findYourAirport() {  
  24.       if($this->myAirplain() == "F22")  
  25.          $this->goToArmyAirport();  
  26.       else 
  27.          $this->goToCivilianAirport();  
  28.    }  
  29.    private function fightEnemy() {  
  30.       $this->aim();  
  31.       $this->prepare();  
  32.       $this->fire();  
  33.    }  

对比两段代码,第二段代码更加简洁、可读和可维护。

13.避免深层嵌套

太多层的嵌套会让代码很难阅读、理解和维护。看看下面的代码:

  1. function doSomething() {  
  2.     if ($someCondition) {  
  3.         if ($someOtherCondition) {  
  4.             if ($yetSomeOtherCondition) {  
  5.                 doSomethingSpecial();  
  6.             }  
  7.             doSomethingElse();  
  8.         }  
  9.     }  

条件里面又嵌套多个条件,通过转换条件,我们对代码进行了调整:

  1. function doSomething() {  
  2.     if (!$someCondition) {  
  3.         return false;  
  4.     }  
  5.     if (!$someOtherCondition) {  
  6.         return false;  
  7.     }  
  8.     if ($yetSomeOtherCondition) {  
  9.         doSomethingSpecial();  
  10.     }  
  11.     doSomethingElse();  
  12. }  

相对于前面的代码,这段代码简洁了很多,并且所实现的功能也是一样的。

当你在if里面使用嵌套,请仔细检查代码,里面可能同时执行多个方法,例如下面这段代码:

  1. function someFunc() {  
  2.    if($oneThing) {  
  3.       $this->doSomething();  
  4.       if($anotherThing)  
  5.          $this->doSomethingElse();  
  6.    }  

这种情况下,可以把嵌套代码提取出来:

  1. function someFunc() {  
  2.    if($oneThing) {  
  3.       $this->doSomething();  
  4.       $this->doAnotherThing($anotherThing);  
  5.    }  
  6. }  
  7. private doAnotherThing($anotherThing) {  
  8.    if($anotherThing)  
  9.       $this->doSomethingElse();  

14.避免使用匿名数字和字符串(Avoid Magic Numbers and Strings)

使用匿名数字和字符串是有害无益的,在代码里定义需要使用的变量和常量。比如下面这段代码:

  1. function someFunct() {  
  2.    $this->order->set(23);  
  3.    $this->order->addProduct('superComputer');  
  4.    $this->shoppingList->add('superComputer');  

给23和“superComputer”赋予相应意义的变量名:

  1. function someFunct() {  
  2.    $orderId = 23;  
  3.    $selectedProductName = 'superComputer';  
  4.    $this->order->set($orderId);  
  5.    $this->order->addProduct($selectedProductName);  
  6.    $this->shoppingList->add($selectedProductName);  

可能会有人认为,一些无意义的变量尽量少定义,虽然它们对性能的影响是微不足道的。但可读性永远处于优先地位。请记住:不要随便优化性能,除非你知道为什么。

15.使用Built-in数组函数

使用built-in函数来代替foreach()

差的代码:

  1. foreach (&$myArray as $key =>$element) {  
  2.    if ($element > 5) unset ($myArray[$key]);  

改进后的代码:

  1. $myArray = array_filter($myArrayfunction ($element) { return $element <= 5;});  

PHP里面提供了许多数组方法。起初会混淆,但是试着花时间好好学学它们。

16.不要过度使用变量

大家在开发过程中很容易使用变量,但请记住,变量是需要存储在内存中的。看下面这段代码:

  1. public function get_posts() {  
  2.    $query = $this->db->get('posts');  
  3.    $result = $query->result();  
  4.    return $result;  

$result变量其实是不需要的。

  1. public function get_posts() {  
  2.    $query = $this->db->get('posts');  
  3.    return $query->result();  

虽然这些差别都是微不足道的,但对于养成良好的编码习惯还是 很重要的。

通用篇

17.依赖数据库引擎

使用数据库来专门处理数据会让你的程序更高效。

例如,在大多数情况下,你可以避免冗余的数据查询。大多数的plug-and-play用户管理脚本在用户注册时都使用了两次数据查询:先检查用户名/邮件是否存在,另外再把用户信息插入到数据库中。一个比较好的做法是在数据库中设置username字段为UNIQUE,然后你可以利用本地的MySQL函数来检查用户名是否存在,然后添加进去。

18.正确命名变量

使用x、y、z命名变量的时代已经结束(除非是处理一个坐标系统)。变量是你逻辑代码的重要组成部分。不想键入长名字吗?获取一个好的IDE吧,现代的IDE可以自动完成变量命名。

19.方法表示动作

见名知意,看到方法名字就知道它执行了哪些动作。使用一个短的,但具有描述性的范围命名(例如:public methods即可这样命名);使用一个长的名字,并且可以更加详细的描述(例如:定义private/protected methods)。这样会让你的代码更加可读可写。

当然也要避免用非英语来进行命名。例如使用“做些什麼()”或者делатьчтото()命名,简直是糟透了的命名。对于其他程序员来说,真的很难理解。尤其是在一个团队里,请记住,让你命名更加规范些吧!

20.结构的定义

最后,我们来说一下代码结构,从可读性和可维护性来讲,代码结构也是相当重要的,下面我们从两方面来讲:

  • 首行缩进4字节或2个标签宽度。
  • 设置合理的线宽(line-width)并且保持。一行只有40个字节?我们已经不是70年代的人了。一行限制在120个字节,并且在屏幕上放一个标签,并且驱使IDE保持。

结论

发生错误不要紧,关键是要总结错误,并且从中吸取教训,只有不断总结和学习,才能让你的编程之路走的更远。

来自:20 All Too Common Coding Pitfalls For Beginners


(转发请注明转自:学PHP)    


  相关推荐



1楼 wotoadgi说: 2015-07-05 03:30:55
@@@ Plans to develop an ambitious new MLS franchise are firmly in place, and David Beckham was on hand to discuss the mooted project during an appearance in Florida with close friend and confidante Dave Gardner on Monday afternoon. The former Manchester United and Real Madrid midfielder exited the offices of American delivery giant DHL with football agent Gardner, less than a day after flying into the coastal city from London. Beckham, 39, looked typically stylish in a smart black blazer and matching jeans following a meeting as he looks to develop a new soccer team, and with it a new stadium, close to the sweeping Miami coastline. Scroll down for video Lads day out: But it was strictly business for David Beckham and close friend Dave Gardner following a day of meetings in Miami on Monday The sporting icon teamed his ensemble with a pair of on-trend Stan Smith trainers courtesy of long-term sponsor Adidas, while his hair was casually swept away from his face.
2楼 Kelis说: 2016-12-21 20:23:29
What a great recsuroe this text is.
3楼 Kelis说: 2016-12-21 20:23:39
What a great recsuroe this text is.

  发表评论
昵称:
(不超过20个字符或10个汉字)
内容: