因為 @公子 公子指出了我在一個 回複 中的錯誤,我才開始逐漸意識到自己已經開始養成了一些很不好的編程習慣,比如嵌套迴圈,比如
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的人都習慣了……
你貼的代碼,之所以難讀,好像和缺少換行和注釋也有關係。