登录  /  注册

code - PHP 开发中有哪些不好的编程习惯需要避免

php中文网
发布: 2016-06-06 20:45:50
原创
1014人浏览过

因为 @公子 公子指出了我在一个 回复 中的错误,我才开始逐渐意识到自己已经开始养成了一些很不好的编程习惯,比如嵌套循环,比如 N 多个条件嵌套,导致 } 符号堆积,以至于代码可读性极差。之前只重视了功能的实现与否,没有忽视了代码的可读性和性能方面的体现。
这边罗列下我所知道的一些不好的编程习惯:
1.嵌套循环
2.过多的条件嵌套
3.用户提交数据不进行过滤
4.函数体过长
5.变量命名清晰

我相信有不少 phper 都读过 《php 最佳实践》,或许我们大家可以集思广益,总结一个《php“最差”实践》,这样也可以当做一个警示录,时刻提醒自己优化代码,希望 php 开发经验丰富的前辈们能不吝赐教。:)

回复内容:

因为 @公子 公子指出了我在一个 回复 中的错误,我才开始逐渐意识到自己已经开始养成了一些很不好的编程习惯,比如嵌套循环,比如 N 多个条件嵌套,导致 } 符号堆积,以至于代码可读性极差。之前只重视了功能的实现与否,没有忽视了代码的可读性和性能方面的体现。
这边罗列下我所知道的一些不好的编程习惯:
1.嵌套循环
2.过多的条件嵌套
3.用户提交数据不进行过滤
4.函数体过长
5.变量命名清晰

我相信有不少 phper 都读过 《php 最佳实践》,或许我们大家可以集思广益,总结一个《php“最差”实践》,这样也可以当做一个警示录,时刻提醒自己优化代码,希望 php 开发经验丰富的前辈们能不吝赐教。:)

1,拼凑SQL,如下

<code class="lang-php">        $sql = "INSERT INTO `#@__archives`(id,typeid,typeid2,sortrank,flag,ismake,channel,arcrank,click,money,title,shorttitle,
        color,writer,source,litpic,pubdate,senddate,mid,voteid,notpost,description,keywords,filename,dutyadmin,weight)
        VALUES ('{$this-&gt;art['id']}','{$this-&gt;art['typeid']}','{$this-&gt;art['typeid2']}','{$this-&gt;art['sortrank']}','{$this-&gt;art['flag']}',
        '{$this-&gt;art['ismake']}','{$this-&gt;art['channelid']}','{$this-&gt;art['arcrank']}','{$this-&gt;art['click']}','{$this-&gt;art['money']}','{$this-&gt;art['title']}',
        '{$this-&gt;art['shorttitle']}','{$this-&gt;art['color']}','{$this-&gt;art['writer']}','{$this-&gt;art['source']}','{$this-&gt;art['litpic']}','{$this-&gt;art['pubdate']}',
        '{$this-&gt;art['senddate']}','{$this-&gt;art['adminid']}','{$this-&gt;art['voteid']}','{$this-&gt;art['notpost']}','{$this-&gt;art['description']}',
        '{$this-&gt;art['keywords']}','{$this-&gt;art['filename']}','{$this-&gt;art['adminid']}','{$this-&gt;art['weight']}');";
</code>
登录后复制

2, 迟迟不肯return,代码挤在一起

<code class="lang-php">function readHosts(){
    global $config;
    $hosts = array();
    $fp = fopen(HOST_FILE, 'r');
    if($fp){
        while(!feof($fp)){
            $line = trim(fgets($fp));
            if($line!='' &amp;&amp; substr($line, 0, 1)!='#'){
                //将多个空格替换为一个,增加容错率
                $line = preg_replace("/\s(?=\s)/","\\1",$line);
                @list($host,$user,$password,$time) = explode(' ', $line);
                $timeline = mktime((int)$time);
                if($host &amp;&amp; $user &amp;&amp; $password){
                    if($timeline  $host,
                            'dbuser' =&gt; $user,
                            'dbpwd' =&gt; $password,
                            'dbname' =&gt; 'mysql',
                            'dbprefix' =&gt; 'dede_',
                            'dbcharset' =&gt; 'gbk',
                        );
                        msg('服务器'.$host.'加入发布列队');
                    }else{
                        msg('服务器'.$host.'没有到发布的时间');
                    }
                }
            }
        }
        echo "\r\n";
    }
    fclose($fp);
    return $hosts;
}
</code>
登录后复制

3, 全局变量global, 以下的msg函数大量调用....

<code class="lang-php">function SendToSite($site){
    global $db,$log,$config;
    if($log-&gt;get_value($site['dbname'])==='finish') return;
    echo "=====================\r\n";
    msg('开始连接到数据库 '.$site['dbname']);
    if($db-&gt;select_db($site['dbname'])){
        msg('连接成功,收集站点信息');
        if($db-&gt;HasTable('archives')){
            msg('找到文章数据表,开始发布');
        }else{
            msg('没有找到文章数据表,可能表前缀不正确,跳过这个站点');
            return;
        }
    }else{
        msg('连接失败,跳过这个站点');
        return;
    }
</code>
登录后复制

4,超长嵌套

<code class="lang-php">    if(count($site_channel)&gt;0) {
        $keylink = '<a href="'.%24site_url.'" target="_blank">'.GBKTOUTF8($site_name).'</a>';
        msg('找到'.count($site_channel).'个文章栏目');
        echo "\r\n";
        foreach ($site_channel as $channel){
            if($log-&gt;get_value($site['dbname'].'_'.$channel['id'])==='finish'){
                msg($site['dbname'].'栏目ID为'.$channel['id'].'今日已发布完成,跳过');
                continue;
            }
            $sendnum = ReadIntFromStr($config['send_num']);
            if($sendnum get_value($site['dbname'].'_'.$channel['id'])){
                continue;
            }
            $keyword_title_num = ReadIntFromStr($config['keyword_title_num']);
            if($keyword_title_num&gt;$sendnum) $keyword_title_num = $sendnum;
            $keyword_titles = array();
            for($i=0;$iget_value($site['dbname'].'_'.$channel['id']);$iart_add($art)){
                            $backupfile=DIR_BACKUP.substr($txtfile, strlen(DIR_TXTFILE));
                            if(!file_exists(dirname($backupfile))) mkdirs(dirname($backupfile));
                            rename($txtfile, $backupfile);
                            msg('添加成功,备份txt文件');
                            $log-&gt;add($site['dbname'].'_'.$channel['id'], $i);
                            $log-&gt;save();
                        }else{
                            msg('文章添加失败');
                        }
                    }else{
                        msg('向 ['.$channel['typename'].'] 中添加文章失败,跳过');
                        continue;
                    }
                }else{
                    msg('没有找到可用的txt文件');
                    break;
                }
                echo "\r\n";
            }
            $log-&gt;add($site['dbname'].'_'.$channel['id'], 'finish');
            $log-&gt;save();
        }
        $log-&gt;add($site['dbname'], 'finish');
        $log-&gt;save();
    }else{
        msg('没有找到文章栏目,跳过这个站点');
        echo "\r\n";
    }
</code>
登录后复制

5, 过多使用@抑制错误,不使用异常处理, 类的方法没有明确声明访问权限.

<code class="lang-php">class db {

    private $config = array(
        'dbhost' =&gt; '',
        'dbname' =&gt; '',
        'dbuser' =&gt; '',
        'dbpwd' =&gt; '',
        'dbprefix' =&gt; '',
        'dbcharset' =&gt; ''
    );
    public $linkID = null;
    public $isconnect = FALSE;

    function __construct($config) {
        $this-&gt;config = $config + $this-&gt;config;
        $this-&gt;connect();
    }

    function connect(){
        if($this-&gt;config['dbhost'] &amp;&amp; $this-&gt;config['dbname']){
            $this-&gt;linkID = @mysql_connect($this-&gt;config['dbhost'], $this-&gt;config['dbuser'], $this-&gt;config['dbpwd']);
            if(!$this-&gt;linkID){
                //连接错误,直接退出
                //echo mysql_error()."\r\n";
                return FALSE;
            }
            if (@mysql_select_db($this-&gt;config['dbname'])) {
                if($this-&gt;config['dbcharset'] != ''){
                    @mysql_query("SET NAMES '{$this-&gt;config['dbcharset']}'", $this-&gt;linkID);
                }
            }
            $this-&gt;isconnect = TRUE;
        }
        return $this-&gt;isconnect;
    }
}
</code>
登录后复制

太多了..不好弄...

https://github.com/justjavac/PHP-Best-Practices-zh_CN

http://youngsterxyf.github.io/2013/06/01/php-best-practices/

http://segmentfault.com/a/1190000000443795

http://wulijun.github.io/php-the-right-way/

http://thisinterestsme.com/php-best-practises/

没仔细看,可能有重复。

常规的别人都会说,我来说点激进的吧

  • 除了全局变量之外,全局function也不允许自己定义
  • 一个php文件里要么只有一个class声明,要么不存在class声明
  • 接上,必须用autoloader来加载类,而且规则越简单越好,PSR标准最好
  • 不允许修改public static $var
  • 参数是对象时必须在签名中声明类型,声明的类型中没有的成员不允许用
  • 不允许给对象动态添加属性。唯一的例外是stdClass
  • 必须使用单入口pattern,而且web server配置的documentroot下只能有index.php一个php文件

<code>$arr = array();
for($i = 0; $i </code>
登录后复制

避免上面这种写法,因为循环每一次都会重新计算一次数组长度,可以这样写:

<code>$arr = array();
$length = count($arr);
for($i = 0; $i </code>
登录后复制

之前翻译过一个针对新手的建议帖子 一共有三篇
其中前两篇有比较多的对于不好用法的分析和解决方案

http://ashitaka.me/%E8%AF%91/2014/01/05/40-php-tips-part-i/
http://ashitaka.me/%E8%AF%91/2014/01/06/40-php-tips-part-ii/

拿自己举例,一个实现合并二维数组相同 key 的写法:
我的 ugly 写法:

<code>$arr1 = array(
    array('num'=&gt;5,'period'=&gt;3),
    array('num'=&gt;10,'period'=&gt;3),
    array('num'=&gt;15,'period'=&gt;9)
);

$arr2 = array();

foreach($arr1 as $k1 =&gt; $v1) {
    if(empty($arr2)) {
        $arr2[] = $v1;
    } else {
        foreach ($arr2 as &amp;$v2) {
            if($v1['period'] == $v2['period']) {
                $v2['num'] += $v1['num'];   
            } else {
                $arr2[] = $v1;
            }
        }
    }
}
</code>
登录后复制

1.不必要的嵌套循环
2.变量命名不清晰
3.} 堆叠使得代码可读性极差

@公子 的规范写法:

<code>rr = array(
    array('num'=&gt;5,'period'=&gt;3),
    array('num'=&gt;10,'period'=&gt;3),
    array('num'=&gt;15,'period'=&gt;9)
);
$temp = array();
foreach($arr as $item) {
    list($n, $p) = array_values($item);
    $temp[$p] =  array_key_exists($p, $temp) ? $temp[$p]+$n : $n;
}

$arr = array();
foreach($temp as $p =&gt; $n)
    $arr[] = array('num'=&gt;$n, 'period'=&gt;$p);

print_r($arr);
</code>
登录后复制

1.拆开循环
2.利用 PHP 自带的数组函数简化了代码
3.代码可读性较强

如果你用netbeans8.0的话,超过2还是3层的嵌套,全局变量的不经判断直接使用,一个方法写的太长(应该对功能拆分).等等,都会直接给出警告提示.一个好的IDE对提高自己的代码书写规范性和可阅读新还是很有帮助的.

慎用&
例子:

<code>$arr = array('a'=&gt;1, 'b'=&gt;2);
foreach($arr as &amp;$v)
{
    if($v == '2')
    {
        $v = 3;
    }
}
$v = 444;
</code>
登录后复制

打印$arr['b'] 的值为 444;

可以改成如下:

<code>$arr = array('a'=&gt;1, 'b'=&gt;2);
foreach($arr as $k =&gt; $v)
{
    if($v == '2')
    {
        $arr[$k] = 3;
    }
}</code>
登录后复制

某些字符串函数与数组函数搞不清哪个是needle哪个是haystack...

js里有一种嵌套回调,层级太深了,也是巨难理解的。不过写过js的人都习惯了……
你贴的代码,之所以难读,好像和缺少换行和注释也有关系。

智能AI问答
PHP中文网智能助手能迅速回答你的编程问题,提供实时的代码和解决方案,帮助你解决各种难题。不仅如此,它还能提供编程资源和学习指导,帮助你快速提升编程技能。无论你是初学者还是专业人士,AI智能助手都能成为你的可靠助手,助力你在编程领域取得更大的成就。
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2024 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号