Press "Enter" to skip to content

一些PHP Coding Tips[2011/04/02最后更新]

以下是一些PHP Coding Tips. 当然, 这些Tips并不一定仅仅局限于PHP.
大家有什么好的心得, 欢迎直接回复本文与更多的人分享.. 谢谢
本文长期更新, 请关注PHP Coding Tips
最后更新: 2011/04/02

  • 1. 使用list来实现一次获取explode后的特定段值:
    list( ,  $mid) = explode(';', $string);
    
  • 2. 使用NULL === 来代替is_null:
    is_null和 NULL === 完全是一样的效果, 但是却节省了一次函数调用.
  • 3. 使用===尽量不用==:
    PHP有俩组相等比较运算符===/!==和==/!=, ==/!=会有隐式类型转换,而===/!==会严格比较俩个操作时是否类型相同并且值相等.
    我们应该尽量使用===而不是==, 除了因为转换规则比较难记以外, 还有一点就是如果使用===, 对于日后的维护或者阅读你代码的人也会很舒服:"在这个时刻, 这一行语句, 这个变量就是这个类型的!".
  • 4. 少用/不用 continue:
    continue是回到循环的头部, 而循环结束本来就是回到循环的头部, 所以通过适当的构造, 我们完全可以避免使用这条语句, 使得效率得到改善.
  • 5. 警惕switch/in_array等的松比较(loose comparision):
    switch和in_array都是采用松比较, 所以在要比较的变量之间类型不一样的时候, 很容易出错:

    	switch ($name) {
    		case "laruence":
    			...
    			break;
    		case "eve":
    			...
    			break;
    	}
    

    对于上面的switch, 如果$name是数字0, 那么它会满足任何一条case. 同理在in_array中也是.
    解决的办法就是, 在switch之前, 把变量类型转换成你所期望的类型.

    switch (strval($name)) {
    	case "laruence":
    		...
    			break;
    	case "eve":
    		...
    			break;
    }
    

    而, in_array提供了第三个可选的参数, 通过这个参数可以改变默认的比较方式.

  • 6. switch不仅仅只用来判别变量:
    比如, 对于如下的一段代码:

    if($a) {
    } else if ($b) {
    } else if ($c || $d) {
    }
    

    可以简单的改写为:

    switch (TRUE) {
    	case $a:
    		break;
    	case $b:
    		break;
    	case $c:
    	case $d:
    		break;
    }
    

    是不是看起来更清晰呢?

  • 7. 变量先定义后使用:
    使用一个未定义的变量, 比使用一个定义好的变量要慢8倍以上!
    可以相像, PHP引擎会首先按照正常的逻辑来获取这个变量, 然而这个变量不存在, 所以PHP引擎需要抛出一个NOTICE, 并且进入一段使用未定义变量时应该走的逻辑, 然后返回一个新的变量.
    另外, 阅读代码的角度讲, 当你使用一个未定义的变量时, 会让阅读你代码的人困惑:"这个变量在那里初始化的, 和之前的代码有关系么? 和include进来的文件有关系么?"
    最后, 从规范编程的角度来讲, 你也需要这样做.
  • 8. 不用第三变量交换俩个变量的值:
    list($a, $b) = array($b, $a),
    

    但其实还是有匿名临时变量的产生, 对于整数来说, 采用互逆的运算来做, 还是比较靠谱:

    	$a = $a + $b;
    	$b = $a - $b;
    	$a = $a - $b;
    

    不过, 还是用异或比较好, 因为+ - * /容易产生精度丢失或者溢出.

  • 9. floor == 俩次非运算(此条由skiyo提供)
    	echo  ~~4.9;
    	echo  floor(4.9);
    

    用俩次非运算的速度基本上是floor的3倍, 不过有一点, 对于大数来说, 可能会发生溢出:

    	echo ~~99999999999999.99; //276447231
    	echo floor(99999999999999.99); //99999999999999
    
  • 10. do{}while(0)妙用(此条由Qianfeng提供)
    我们知道do{}while(0)在c/c++中, 有很多妙用, 比如消除goto, 宏定义代码块.
    所以, PHP中同理, 也可以用do{}while(0)来做一些巧妙的应用

    	do{
    		if(true) {
    			break;
    		}
    		if(true) {
    			break;
    		}
    	} while(false);
    //好过
    	if(true) {
    	} else if(true) {
    	} else {
    	}
    
  • 11. 尽量少用@错误抑制符
    如下代码:

    @func();
    

    就相当于(参见深入理解PHP原理之错误抑制与内嵌HTML):

    $report = error_reporting(0);
    func();
    error_reporting($report);
    

    另外错误抑制符号, 可能会造成一些问题, 参看(PHP错误抑制符(@)导致引用传参失败的Bug);
    最后,错误抑制符在发生错误调试的时候也可能会带来麻烦.

  • 12. 尽量避免使用递归(此条来自lazyboy)
    递归性能堪忧, 而大部分的递归都是尾递归, 都是可以消除的.

    function f($n) {
       if ($n = 0) return 1;
       return $n * f($n - 1);
    }
    //变为:
    $result = 1;
    for ($y = 1; $y < $n + 1; $y++ ) {
    	$result *= $y;
    }
    
  • 13. 使用$_SERVER['REQUEST_TIME']代替time()
    time()会引来一次函数调用, 而如果对时间的精确值要求不高, 可以使用$_SERVER['REQUEST_TIME']代替, 快很多.
  • 14. 避免在for判断条件中做运算(此条来自留言的Anonymous)
    如下的代码:

    for($i=0; $i<strlen($str); $i++) {
    }
    

    会导致每次循环都调用strlen, 改为

    for ($i=0, $j=strlen($str); $i<$j; $i++) {
    }
    
  • 15. 尽量避免使用正则(此条来自pangyontao)
    正则耗时, 尽量避免, 而采用直接的字符串处理函数代替, 如:

    if (preg_match("!^foo_!i", "FoO_")) { }
    // 替换为:
    if (!strncasecmp("foo_", "FoO_", 4)) { }
    if (preg_match("![a8f9]!", "sometext")) { }
    // 替换为:
    if (strpbrk("a8f9", "sometext")) { }
    if (preg_match("!string!i", "text")) {}
    // 替换为:
    if (stripos("text", "string") !== false) {} 
    

    等等.

  • 16. 用大括号括起在双引号和heredoc中的变量
    如下的代码:

    echo "$name[2]";
    

    PHP不知道程序员的意图是$name . "[2]"还是$name[2],
    所以建议, 都加上大括号:

    echo "{$name}[2]";
    //或者
    echo "${name}[2]";
    
  • 17. 用FALSE表示错误, 用NULL表示不存在.
    对于操作类的函数, 失败返回FALSE, 表示"操作失败了", 而对于查询类的函数, 如果找不到想要的值, 则应该返回NULL, 表示"找不到".
  • 53 Comments

    1. casa98
      casa98 January 6, 2020

      Online football betting, single ball betting, Teng ball ball step

    2. Gclub
      Gclub June 15, 2019

      You are very good at that.

    3. German Biddell
      German Biddell February 10, 2017

      I’m amazed, I must say. Rarely do I come across a blog that’s both equally educative and entertaining, and
      without a doubt, you have hit the nail on the head.
      The issue is something that not enough men and women are speaking intelligently about.
      Now i’m very happy I came across this in my search for something regarding this.

    4. leslie
      leslie February 2, 2015

      有一些是不可取的,几乎可以忽略的细微效率提高导致代码可读性的大幅下降;
      用异或交换变量当两个变量类型不一致会产生问题;

    5. domain
      domain September 29, 2014

      I visit each day some blogs and sites to read posts, except this blog
      presents quality based articles.

    6. Anew_G.
      Anew_G. May 4, 2013

      if (strpbrk(“a8f9”, “sometext”)) { }
      参数写反了吧?

    7. David
      David February 6, 2013

      写代码要精益求精。

    8. 须臾念北
      须臾念北 February 7, 2012

      if($a === “condition”){
      return true;
      } else {
      return false;
      }
      改为:
      return $a === “condition”;

    9. pplxh
      pplxh December 28, 2011

      我是来顶鸟哥的~~~很受用,收了~~

    10. foxling
      foxling September 26, 2011

      请教了
      对于“使用一个未定义的变量, 比使用一个定义好的变量要慢8倍以上!” 很震惊,但没有明白这里的定义变量的意思。
      php有定义变量的方式?
      直接在代码前写上?
      $var;
      或者通过默认赋值来定义?
      $var = ”;

    11. Me.strone
      Me.strone September 18, 2011

      学习了,好东西,多谢博主分享。

    12. ryan
      ryan April 7, 2011

      第一条中的规律适合只适合5.2,我在我5.3的机器上反而是普通的要更快一些,不过在5.2版本的机器上,list更快一些。
      我不建议将这条作为标准~~~~

    13. ryan
      ryan April 6, 2011

      如果是一个获取数组的函数,如果获取的内容为空,最好返回空数组,这样在外层不需要做额外的判断
      $ret = array();
      if ($from_db) {
      $ret = get_list($from_db);
      }
      return $ret;
      要比
      if ($from_db) {
      $ret = get_list($from_db);
      }
      return $ret;
      要好很多

    14. wilson
      wilson April 6, 2011

      学习了

    15. 雪候鸟
      雪候鸟 April 2, 2011

      17. 用FALSE表示错误, 用NULL表示不存在.
      对于操作类的函数, 失败返回FALSE, 表示”操作失败了”, 而对于查询类的函数, 如果找不到想要的值, 则应该返回NULL, 表示”找不到”.

    16. hibin
      hibin April 1, 2011

      果断收藏

    17. 雪候鸟
      雪候鸟 March 31, 2011

      @horseluke 哦? 我还真没注意, 回去看看

    18. 雪候鸟
      雪候鸟 March 31, 2011

      @pangyongtao 对于Apache2handler, 可以简单调用:getallheaders, 另外, 也不应该使用preg_match, 使用strncmp代替

    19. pangyongtao
      pangyongtao March 31, 2011

      php中获取全部的header(来自 chengen)
      foreach( $_SERVER as $k=>$v ){
      if( preg_match(“#HTTP_(.+)#”,$k,$hp) ){
      array_push( $headers, “$k:$v”);
      }
      }

    20. horseluke
      horseluke March 31, 2011

      @雪候鸟 ,刚才测试了一下,发现在php 5.3中,phpinfo中的env部分和$_ENV已经完全隔离开来,具体表现有:
      1、初始化的$_ENV已经成为了一个空数组
      2、无论是否处在safe mode下,putenv都已经不能修改phpinfo中的env。
      看来可能就是怕出现你所说的问题了~

    21. 小蔡
      小蔡 March 31, 2011

      呵呵,“使用$_SERVER[‘REQUEST_TIME’]代替tiem()”,有点小误,time写错了

    22. 雪候鸟
      雪候鸟 March 30, 2011

      @horseluke @pangyongtao 如果不小心phpinfo被人看了,,,就Over了.

    23. horseluke
      horseluke March 30, 2011

      再@pangyongtao,测试了一下,发现仅对putenv/getenv有影响。收回刚才说的话~

    24. horseluke
      horseluke March 30, 2011

      @pangyongtao ,在我的印象中,有点服务器在安全模式下是会变态到不允许更改$_ENV值(受php.ini的safe_mode_protected_env_vars, safe_mode_allowed_env_vars影响)。
      当然真遇到那就自认倒霉了~

    25. Once
      Once March 30, 2011

      鸟哥v5~ 好文章收藏:)

    26. 雪候鸟
      雪候鸟 March 30, 2011

      @lazyboy 第四条不行,,,js才可以,呵呵, PHP中逻辑运算返回的是boolean值, 所以$d最后的结果只能是TRUE和FALSE

    27. lazyboy
      lazyboy March 30, 2011

      我也来贡献几条:
      1. 尽量减少@来抑制错误,而是用try/catch
      例如 @mysql_contect();
      改成
      try{
      mysql_contect();
      } catch(Execption $e) {
      // 说不定那天你就想看看这里错误的原因
      }
      2. 能用[]这个的时候,就别用array_push
      array_push($arr, ‘aaa’);
      改成
      $arr[] = ‘aaa’;
      3. 能用循环实现的方式,就别用递归了
      4. 运算表达式的妙用
      if($a || $b) {
      if($a) {
      $d = $a;
      } else {
      $d = $b;
      }
      } else {
      $d = $c;
      }
      $d = $a || $b || $c;

    28. k4shifz
      k4shifz March 29, 2011

      长期关注,希望风雪牛坚持更新

    29. Anonymous
      Anonymous March 26, 2011

      我也贡献几条吧。。
      使用for循环的时候用
      for ($i=count($res);$i>=0;$i–) {
      do_sth($res[i]);
      }
      好过
      for ($i=0;$i<count($res);$i++) {
      do_sth($res[i]);
      }
      查看自己的脚本用了多少内存
      memory_get_usage()
      单位是字节
      写脚本的时候记得unset对象或者大数组
      不知道哪里用了内存,就用上面的方法跟踪
      查看自己的脚本执行了多久了
      time()-$_SERVER['REQUEST_TIME']
      精度是秒。。
      那个~~代替floor的方法不好,会带来可读性的问题。
      除非追求的是片面的短,那么用9.99|0也可以实现,不过我还是觉得追求速度的用(int)9.99当floor比较靠谱。。
      该死的验证码,超时了,害我白写了。再加个tips: 发帖之前先刷新验证码

    30. Qianfeng
      Qianfeng March 25, 2011

      do
      {
      if(true)
      {
      break;
      }
      if(true)
      {
      break;
      }
      //@TODO:do some thing
      }while(false);
      好过
      if(true)
      {
      }
      else if(true)
      {
      }
      else
      {
      }
      你懂的..

    31. pangyongtao
      pangyongtao March 25, 2011

      1、可以使用下标访问字符串 $neighbor = ‘Hilda’; print $neighbor[3];
      d
      2、Heredoc有用的很 print <<< HTML
      There are $remaining_cards left.
      $text
      HTML;
      3、字符串替换 $credit_card = ‘4111 1111 1111 1111’;
      Print ubstr_replace($credit_card,’xxxx ‘,0,strlen($credit_card)-4);
      xxxx 1111
      4、遍历字符串中的每个字符 for ($i = 0, $j = strlen($string); $i here am I
      6、你懂的 ltrim(’10 PRINT A$’,’ 0..9′);
      7、正则切 split(‘ +’,’This sentence has some extra whitespace in it.’);
      8、$newtext = wordwrap($text, 20, “\n”);
      The quick brown fox
      jumped over the lazy
      dog.
      9、判断2个浮点数是否相同 $delta = 0.00001;
      $a = 1.00000001;
      $b = 1.00000000;
      if (abs($a – $b) array(‘Red’, ‘White’, ‘Blue’),
      ‘cities’ => array(‘Boston’, ‘New York’, ‘Chicago’));
      array_multisort($stuff[‘colors’], $stuff[‘cities’]);
      18、交换变量 list($a,$b,$c) = array($c,$b,$a);
      19、共享内存 sem_get sem_acquire shm_attach shm_get_var shm_put_var
      shm_detach sem_release
      20、唯一id $unique_id = uniqid(microtime(),1);
      21、Transforming XML with XSLT xslt_create xslt_process xslt_free
      22、用环境变量存密码 mysql_connect(‘localhost’,$_ENV[‘MYSQL_USER’],$_ENV[‘MYSQL_PASSWORD’]);
      23、把信息隐藏在页面上,而不是原样展示 base64_encode(serialize($personal_data));
      24、PHP’s mcrypt extension
      25、SSL是否使用 if (‘on’ == $_SERVER[‘HTTPS’])

    32. 飞晏
      飞晏 March 24, 2011

      有些经验,但是比较肤浅,还是等待各位前辈的经验吧。

    33. cyberty
      cyberty March 24, 2011

      “不用第三变量交换俩个变量的值”
      请问, 这个是有效率问题么?

    34. maker
      maker March 24, 2011

      好东西,收藏,期待更多好文.

    35. solu
      solu March 24, 2011

      学习了,表示会长期关注。

    36. Lotte
      Lotte March 24, 2011

      强人,希望学到更多PHP知识!

    37. gsid
      gsid March 24, 2011

      长期关注本文,只盼更新频率快

    Leave a Reply

    Your email address will not be published. Required fields are marked *