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

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

WBOY
Freigeben: 2016-06-06 20:45:50
Original
1212 Leute haben es durchsucht

因为 @公子 公子指出了我在一个 回复 中的错误,我才开始逐渐意识到自己已经开始养成了一些很不好的编程习惯,比如嵌套循环,比如 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->art['id']}','{$this->art['typeid']}','{$this->art['typeid2']}','{$this->art['sortrank']}','{$this->art['flag']}',
        '{$this->art['ismake']}','{$this->art['channelid']}','{$this->art['arcrank']}','{$this->art['click']}','{$this->art['money']}','{$this->art['title']}',
        '{$this->art['shorttitle']}','{$this->art['color']}','{$this->art['writer']}','{$this->art['source']}','{$this->art['litpic']}','{$this->art['pubdate']}',
        '{$this->art['senddate']}','{$this->art['adminid']}','{$this->art['voteid']}','{$this->art['notpost']}','{$this->art['description']}',
        '{$this->art['keywords']}','{$this->art['filename']}','{$this->art['adminid']}','{$this->art['weight']}');";
</code>
Nach dem Login kopieren

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!='' && substr($line, 0, 1)!='#'){
                //将多个空格替换为一个,增加容错率
                $line = preg_replace("/\s(?=\s)/","\\1",$line);
                @list($host,$user,$password,$time) = explode(' ', $line);
                $timeline = mktime((int)$time);
                if($host && $user && $password){
                    if($timeline  $host,
                            'dbuser' => $user,
                            'dbpwd' => $password,
                            'dbname' => 'mysql',
                            'dbprefix' => 'dede_',
                            'dbcharset' => 'gbk',
                        );
                        msg('服务器'.$host.'加入发布列队');
                    }else{
                        msg('服务器'.$host.'没有到发布的时间');
                    }
                }
            }
        }
        echo "\r\n";
    }
    fclose($fp);
    return $hosts;
}
</code>
Nach dem Login kopieren

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

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

4,超长嵌套

<code class="lang-php">    if(count($site_channel)>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->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>$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->add($site['dbname'].'_'.$channel['id'], $i);
                            $log->save();
                        }else{
                            msg('文章添加失败');
                        }
                    }else{
                        msg('向 ['.$channel['typename'].'] 中添加文章失败,跳过');
                        continue;
                    }
                }else{
                    msg('没有找到可用的txt文件');
                    break;
                }
                echo "\r\n";
            }
            $log->add($site['dbname'].'_'.$channel['id'], 'finish');
            $log->save();
        }
        $log->add($site['dbname'], 'finish');
        $log->save();
    }else{
        msg('没有找到文章栏目,跳过这个站点');
        echo "\r\n";
    }
</code>
Nach dem Login kopieren

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

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

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

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

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

太多了..不好弄...

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>
Nach dem Login kopieren

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

<code>$arr = array();
$length = count($arr);
for($i = 0; $i </code>
Nach dem Login kopieren

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

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'=>5,'period'=>3),
    array('num'=>10,'period'=>3),
    array('num'=>15,'period'=>9)
);

$arr2 = array();

foreach($arr1 as $k1 => $v1) {
    if(empty($arr2)) {
        $arr2[] = $v1;
    } else {
        foreach ($arr2 as &$v2) {
            if($v1['period'] == $v2['period']) {
                $v2['num'] += $v1['num'];   
            } else {
                $arr2[] = $v1;
            }
        }
    }
}
</code>
Nach dem Login kopieren

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

@公子 的规范写法:

<code>rr = array(
    array('num'=>5,'period'=>3),
    array('num'=>10,'period'=>3),
    array('num'=>15,'period'=>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 => $n)
    $arr[] = array('num'=>$n, 'period'=>$p);

print_r($arr);
</code>
Nach dem Login kopieren

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

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

慎用&
例子:

<code>$arr = array('a'=>1, 'b'=>2);
foreach($arr as &$v)
{
    if($v == '2')
    {
        $v = 3;
    }
}
$v = 444;
</code>
Nach dem Login kopieren

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

可以改成如下:

<code>$arr = array('a'=>1, 'b'=>2);
foreach($arr as $k => $v)
{
    if($v == '2')
    {
        $arr[$k] = 3;
    }
}</code>
Nach dem Login kopieren

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

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

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage