code - PHP 開發中有哪些不好的編程習慣需要避免

來源:互聯網
上載者:User
因為 @公子 公子指出了我在一個 回複 中的錯誤,我才開始逐漸意識到自己已經開始養成了一些很不好的編程習慣,比如嵌套迴圈,比如 N 多個條件嵌套,導致 } 符號堆積,以至於代碼可讀性極差。之前只重視了功能的實現與否,沒有忽視了代碼的可讀性和效能方面的體現。
這邊羅列下我所知道的一些不好的編程習慣:
1.嵌套迴圈
2.過多的條件嵌套
3.使用者提交資料不進行過濾
4.函數體過長
5.變數命名清晰

我相信有不少 PHPer 都讀過 《PHP 最佳實務》,或許我們大家可以集思廣益,總結一個《PHP“最差”實踐》,這樣也可以當做一個警示錄,時刻提醒自己最佳化代碼,希望 PHP 開發經驗豐富的前輩們能不吝賜教。:)

回複內容:

因為 @公子 公子指出了我在一個 回複 中的錯誤,我才開始逐漸意識到自己已經開始養成了一些很不好的編程習慣,比如嵌套迴圈,比如 N 多個條件嵌套,導致 } 符號堆積,以至於代碼可讀性極差。之前只重視了功能的實現與否,沒有忽視了代碼的可讀性和效能方面的體現。
這邊羅列下我所知道的一些不好的編程習慣:
1.嵌套迴圈
2.過多的條件嵌套
3.使用者提交資料不進行過濾
4.函數體過長
5.變數命名清晰

我相信有不少 PHPer 都讀過 《PHP 最佳實務》,或許我們大家可以集思廣益,總結一個《PHP“最差”實踐》,這樣也可以當做一個警示錄,時刻提醒自己最佳化代碼,希望 PHP 開發經驗豐富的前輩們能不吝賜教。:)

1,拼湊SQL,如下

        $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']}');";

2, 遲遲不肯return,代碼擠在一起

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 <= time()){                        $hosts[] = array(                            'dbhost' => $host,                            'dbuser' => $user,                            'dbpwd' => $password,                            'dbname' => 'mysql',                            'dbprefix' => 'dede_',                            'dbcharset' => 'gbk',                        );                        msg('伺服器'.$host.'加入發布列隊');                    }else{                        msg('伺服器'.$host.'沒有到發布的時間');                    }                }            }        }        echo "\r\n";    }    fclose($fp);    return $hosts;}

3, 全域變數global, 以下的msg函數大量調用....

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;    }

4,超長嵌套

    if(count($site_channel)>0) {        $keylink = ''.GBKTOUTF8($site_name).'';        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 <= $log->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;$i<$keyword_title_num;$i++){                $num = rand(0,$sendnum);                if(!in_array($num, $keyword_titles)){                    $keyword_titles[] = $num;                }else{                    $i--;                    continue;                }            }            $channel = array_map('GBKTOUTF8', $channel);            msg($channel['typename'].'將發布'.$sendnum.'篇文章');            for($i=$log->get_value($site['dbname'].'_'.$channel['id']);$i<$sendnum;$i++){                $txtfile = GetArtFile(DIR_TXTFILE);                if($txtfile){                    if(in_array($i, $keyword_titles)){                        $art = GetArtContent($channel['id'], $txtfile, $keylink, GBKTOUTF8($site_name));                    }else{                        $art = GetArtContent($channel['id'], $txtfile, $keylink);                    }                    if($art){                        msg('正在向 ['.$channel['typename'].'] 中添加文章 《'.$art['title'].'》');                        if($model->art_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";    }

5, 過多使用@抑制錯誤,不使用異常處理, 類的方法沒有明確聲明存取權限.

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;    }}

太多了..不好弄...

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檔案

$arr = array();for($i = 0; $i < count($arr);$i ++){   //code here.}

避免上面這種寫法,因為迴圈每一次都會重新計算一次數組長度,可以這樣寫:

$arr = array();$length = count($arr);for($i = 0; $i < $length;$i ++){   //code here.}

之前翻譯過一個針對新手的建議文章 一共有三篇
其中前兩篇有比較多的對於不好用法的分析和解決方案

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 寫法:

$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;            }        }    }}

1.不必要的嵌套迴圈
2.變數命名不清晰
3.} 堆疊使得代碼可讀性極差

@公子 的規範寫法:

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);

1.拆開迴圈
2.利用 PHP 內建的數組函數簡化了代碼
3.代碼可讀性較強

如果你用netbeans8.0的話,超過2還是3層的嵌套,全域變數的不經判斷直接使用,一個方法寫的太長(應該對功能拆分).等等,都會直接給出警告提示.一個好的IDE對提高自己的代碼書寫規範性和可閱讀新還是很有協助的.

慎用&
例子:

$arr = array('a'=>1, 'b'=>2);foreach($arr as &$v){    if($v == '2')    {        $v = 3;    }}$v = 444;

列印$arr['b'] 的值為 444;

可以改成如下:

$arr = array('a'=>1, 'b'=>2);foreach($arr as $k => $v){    if($v == '2')    {        $arr[$k] = 3;    }}

某些字串函數與數組函數搞不清哪個是needle哪個是haystack...

js裡有一種嵌套回調,層級太深了,也是巨難理解的。不過寫過js的人都習慣了……
你貼的代碼,之所以難讀,好像和缺少換行和注釋也有關係。

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.