|
有些人問,優(yōu)秀程序員和大牛有什么區(qū)別,大概有10到20種吧。因為大牛有很好的編程習慣和豐富的經(jīng)驗,所以他們非常的高效。如果不好的編程習慣出現(xiàn)在你的代碼里,你的代碼效率就會降低。本文闡述一些好的編程習慣,他們可以讓你成為更好的程序員。 這些習慣能讓你的代碼在高效運行的同時提高可維護性。你寫代碼的時候,可能大部分時間都浪費在維護上了,程序的維護代價很高。培養(yǎng)良好的編程習慣,如模塊化設計,可以讓你的代碼可讀性更好,從而容易維護。 代碼中的問題往往伴隨著不良的編程習慣,而且后者會導致代碼不好修改并可能出現(xiàn)新的缺陷。下面有五個好的編程習慣,將幫你避免這些陷阱: 使用友好的命名方式。 使用更精悍短小的代碼。 注釋你的代碼。 編寫異常處理。 永遠,永遠不要復制粘貼. 下面的章節(jié)將解釋這些習慣。 良好的命名方式是最重要的編程習慣,因為好的命名會讓代碼易懂,好懂。代碼的可讀性決定它的可維護性。即使你在代碼沒有寫注釋,如果它可讀性好的話,它也修改起來也會簡單。你應該在練習開時就使用良好的命名方式,讓你的代碼像一本書一樣。 例1包含一個過短的變量名,寫出這樣的代碼非常不好弄懂,而且函數(shù)名也沒有清晰的描述出這個方法是做什么的。函數(shù)名表示了函數(shù)的功能,如果它卻是做別的用途的,那就會誤導別人。 <?php function getNBDay($d) { switch($d) { case 5: case 6: case 7: return 1; default: return ($d + 1); } } $day = 5; $nextDay = getNBDay($day); echo ("Next day is: " . $nextDay . "
"); ?> 例2則給出了使用良好命名方式的代碼。重新命名函數(shù)是為了更好的反映它們的功能。變量也重新命名為描述性的。只有一個在循環(huán)中的$i還使用短的變量名。盡管有些人不同意,短變量名在循環(huán)中是請允許的——甚至更好些,因為它們清晰的起到了指針的功能。 <?php define ('MONDAY', 1); define ('TUESDAY', 2); define ('WEDNESDAY', 3); define ('THURSDAY', 4); define ('FRIDAY', 5); define ('SATURDAY', 6); define ('SUNDAY', 7); /* * * @param $dayOfWeek * @return int Day of week, with 1 being Monday and so on. */ function findNextBusinessDay($dayOfWeek) { $nextBusinessDay = $dayOfWeek; switch($dayOfWeek) { case FRIDAY: case SATURDAY: case SUNDAY: $nextBusinessDay = MONDAY; break; default: $nextBusinessDay += 1; break; } return $nextBusinessDay; } $day = FRIDAY; $nextBusDay = findNextBusinessDay($day); echo ("Next day is:" . $nextBusDay . "
"); 我鼓勵你在函數(shù)中分隔長的條件給函數(shù)命名,以便于描述這個條件。(玉米:這句話啥意思? 5555)這個技巧會讓你的代碼容易閱讀和擴展,因此它可以被抽象復用。如果條件發(fā)生了改變,這樣也會很容易更新函數(shù).由于方法有一個見名知義的名字,化碼就不會失去它本來的意思或者變得難以理解。 使用更少的代碼 編寫代碼、解決問題是一種容易的事情。當你解決一個正在發(fā)生的問題,編呀編,寫呀寫,你的方法越來越長。只要你回頭使用更少的代碼來重構,就是過了很久也沒什么問題。 重構是個好主意,但你應該養(yǎng)成第一次就寫出更短小精悍代碼的習慣。在一個窗口上(玉米:不用翻頁)就能看全的短小函數(shù)更容易理解。要是一個函數(shù)長出了窗口,就很難理解了,因為你不能快速的從頭到腳的瀏覽整個代碼。 當構思一個方法的時候,你還應該養(yǎng)成一個讓它們只做一件事情的習慣。以下因素寫代碼時應常注意。第一,只做一件事情的函數(shù)更易于復用。第二,這樣的函數(shù)測試更方便。第三,這樣的函數(shù)好讀易懂方便改——如果必要的話——讓它們盡可能的簡單吧。 壞習慣:過長的函數(shù)(很多時候) 例三是過長函數(shù)的表現(xiàn)。它不知道自己要做什么。它做太多的事情,所以沒有集成化。它更難以理解,不好Debug和測試。它遍歷文件建立列表,它給對象賦值,它做一些計算,……它耕田,它澆水,甚至做更多事情。(^_^) 例三. 壞習慣:過長函數(shù) <?php function writeRssFeed($user) { // get the DB connection information // look up the user's preferences... $link = mysql_connect('mysql_host', 'mysql_user', 'mysql_password') OR die(mysql_error()); // Query $perfsQuery = sprintf("SELECT max_stories FROM user_perfs WHERE user= '%s'", mysql_real_escape_string($user)); $result = mysql_query($query, $link); $max_stories = 25; // default it to 25; if ($row = mysql_fetch_assoc($result)) { $max_stories = $row['max_stories']; } // go get my data $perfsQuery = sprintf("SELECT * FROM stories WHERE post_Date = '%s'", mysql_real_escape_string()); $result = mysql_query($query, $link); $feed = "<rss version="2.0">" . "<channel>" . "<title>My Great Feed</title>" . "<link>;/link>" . "<description>The best feed in the world</description>" . "<language>en-us</language>" . "<pubDate>Tue, 20 Oct 2008 10:00:00 GMT</pubDate>" . "<lastBuildDate>Tue, 20 Oct 2008 10:00:00 GMT</lastBuildDate>" . "<docs>;/docs>" . "<generator>MyFeed Generator</generator>" . "<managingEditor>[email protected]</managingEditor>" . "<webMaster>[email protected]</webMaster>" . "<ttl>5</ttl>"; // build the feed... while ($row = mysql_fetch_assoc($result)) { $title = $row['title']; $link = $row['link']; $description = $row['description']; $date = $row['date']; $guid = $row['guid']; $feed .= "<item>"; $feed .= "<title>" . $title . "</title>"; $feed .= "<link>" . $link . "</link>"; $feed .= "<description> " . $description . "</description>"; $feed .= "<pubDate>" . $date . "</pubDate>"; $feed .= "<guid>" . $guid . "</guid>"; $feed .= "</item>"; } $feed .= "</rss"; // write the feed out to the server... echo($feed); } ?> 要是你再加更多東西到這個函數(shù)里,它會很快變得難以維護。 好習慣:可管理,集成化的函數(shù) <?php function createRssHeader() { return "<rss version="2.0">" . "<channel>" . "<title>My Great Feed</title>" . "<link>;/link>" . "<description>The best feed in the world</description>" . "<language>en-us</language>" . "<pubDate>Tue, 20 Oct 2008 10:00:00 GMT</pubDate>" . "<lastBuildDate>Tue, 20 Oct 2008 10:00:00 GMT</lastBuildDate>" . "<docs>;/docs>" . "<generator>MyFeed Generator</generator>" . "<managingEditor>[email protected]</managingEditor>" . "<webMaster>[email protected]</webMaster>" . "<ttl>5</ttl>"; } function createRssFooter() { return "</channel></rss>"; } function createRssItem($title, $link, $desc, $date, $guid) { $item .= "<item>"; $item .= "<title>" . $title . "</title>"; $item .= "<link>" . $link . "</link>"; $item .= "<description> " . $description . "</description>"; $item .= "<pubDate>" . $date . "</pubDate>"; $item .= "<guid>" . $guid . "</guid>"; $item .= "</item>"; return $item; } function getUsermaxStories($db_link, $default) { $perfsQuery = sprintf("SELECT max_stories FROM user_perfs WHERE user= '%s'", mysql_real_escape_string($user)); $result = mysql_query($perfsQuery, $db_link); $max_stories = $default; if ($row = mysql_fetch_assoc($result)) { $max_stories = $row['max_stories']; } return $max_stories; } function writeRssFeed($user) { // get the DB connection information $settings = parse_ini_file("rss_server.ini"); // look up the user's preferences... $link = mysql_connect($settings['db_host'], $settings['user'], $settings['password']) OR die(mysql_error()); $max_stories = getUserMaxStories($link, 25); // go get my data $newsQuery = sprintf("SELECT * FROM stories WHERE post_Date = '%s'", mysql_real_escape_string(time())); $result = mysql_query($newsQuery, $link); $feed = createRssHeader(); $i = 0; // build the feed... while ($row = mysql_fetch_assoc($result)) { if ($i < $max_stories) { $title = $row['title']; $link = $row['link']; $description = $row['description']; $Date = $row['Date']; $guid = $row['guid']; $feed .= createRssItem($title, $link, $description, $date, $guid); $i++; } else { break; } } mysql_close($link); $feed .= createRssFooter(); // write the feed out to the server... echo($feed); } ?> 把長函數(shù)分割會導致效率降低,所以要注意,這個好習慣不要使用過度。這樣做可能也會引起閱讀性差,跟原來人家是一個整體時沒什么區(qū)別。 注釋代碼 注釋你的代碼有時就像你剛著手寫代碼一樣困難。明確注釋內(nèi)容很棘手,因為他要寫出代碼要做什么。注釋變量是一個好主意。在函數(shù)頭部注釋可能不太明顯時,就可以告訴閱讀者函數(shù)要什么參數(shù),有什么返回以及主要的意圖。 通常大家會注釋代碼是做什么的,但這并不必要。如果代碼讓人困惑以至于你不得不寫注釋說它是做什么的,這就提示你應該重寫它,使它更好懂。命名良好、更加短小、組織合理的代碼習慣會讓你的代碼用不著注釋就擁有很高的可讀性。 壞習慣:壓根沒有或者嘰嘰歪歪的函數(shù)注釋(^_^) 例5的注釋只給出了代碼在做什么——它的通過循環(huán)的遍歷、加了個數(shù)。但是丟了為什么這么做和要做什么。這會讓別人難以不影響原代碼的情形下安全修改的做出修改。 例5 :壓根沒胡或者嘰嘰歪歪的函數(shù)注釋 <?php class ResultMessage { private $severity; private $Message; public function __construct($sev, $msg) { $this->severity = $sev; $this->Message = $msg; } public function getSeverity() { return $this->severity; } public function setSeverity($severity) { $this->severity = $severity; } public function getMessage() { return $this->Message; } public function setMessage($msg) { $this->message = $msg; } } function cntMsgs($messages) { $n = 0; /* iterate through the messages... */ foreach($messages as $m) { if ($m->getSeverity() == 'Error') { $n++; // add one to the result; } } return $n; } $messages = array(new ResultMessage("Error", "This is an error!"), new ResultMessage("Warning", "This is a warning!"), new ResultMessage("Error", "This is another error!")); $errs = cntMsgs($messages); echo("There are " . $errs . " errors in the result.
"); ?> 好習慣:注釋函數(shù)和類 例6里的注釋標明了類和函數(shù)的意圖。注釋表明方法做了什么和為什么做,這會對將來了解代碼的意圖很有幫助。環(huán)境的變化會需要你進行代碼修改,這就會讓很容易的知道開始時你代碼是做什么的。 例6.好習慣:注釋函數(shù)和類 <?php * The ResultMessage class holds a Message that can be returned * as a result of a process. The Message has a severity and * message. * * @author nagood * */ class ResultMessage { private $severity; private $message; /** * Constructor for the ResultMessage that allows you to assign * severity and meswww.shanxiwang.netsage. * @param $sev See {@link getSeverity()} * @param $msg * @return unknown_type */ public function __construct($sev, $msg) { $this->severity = $sev; $this->message = $msg; } /** * returns the severity of the message. Should be one * "Information", "Warning", or "Error". * @return string Message severity */ public function getSeverity() { return $this->severity; } /** * Sets the severity of the message * @param $severity * @return void */ public function setSeverity($severity) { $this->severity = $severity; public function getMessage() { return $this->Message; } public function setMessage($msg) { $this->message = $msg; } } /* * Counts the messages with the given severity in the array * of messages. * * @param $messages An array of ResultMessage * @return int Count of messages with a severity of "Error" */ function countErrors($messages) { $matchingCount = 0; foreach($messages as $m) { if ($m->getSeverity() == "Error") { $matchingCount++; } } return $matchingCount; } $messages = array(new ResultMessage("Error", "This is an error!"), new ResultMessage("Warning", "This is a warning!"), new ResultMessage("Error", "This is another error!")); $errs = countErrors($messages); echo("There are " . $errs . " errors in the result.
"); ?> 異常處理 寫健壯應用時經(jīng)常會提到的異常處理,一般遵循著80/20原則:80%的代碼用于處理異?;蛘唑炞C,20%的代碼沒什么實際的用途。原始的代碼通常都是在樂觀的環(huán)境下編寫的。這意味著代碼可以在數(shù)據(jù)正常、一切理解的基礎環(huán)境中工作的很好。但是這種代碼在其生命周期內(nèi)是脆弱的。在極端的情形中,你得花更多的時間來未很可能永遠不會發(fā)生的狀況編寫相應代碼。 這個習慣就是要你處理全部的出錯情況,而且如果要是不這么做,你的代碼永遠也完不成。壞習慣:不處理任何異常 <?php // get the actual name of the function convertDayOfWeekToName($day) { $dayNames = array( "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"); return $dayNames[$day]; } echo("The name of the 0 day is: " . convertDayOfWeekToName(0) . "
"); echo("The name of the 10 day is: " . convertDayOfWeekToName(10) . "
"); echo("The name of the 'orange' day is: " . convertDayOfWeekToName('orange') . "
"); ?> 好習慣:防守型編程 例8表明處理并拋出異常是一件很有意義的事情。不只是額外的異常處理可以讓代碼健壯,但是這有助于提高代碼的可讀性。這種異常處理為原作者查看何時編寫提供了一個很好的說明。 例8.好習慣:防守型編程 <?php /** * This is the exception thrown if the day of the week is invalid. * @author nagood * */ class InvalidDayOfWeekException extends Exception { } class InvalidDayFormatException extends Exception { } /** * gets the name of the day given the day in the week. Will * return an error if the value supplied is out of range. * * @param $day * @return unknown_type */ function convertDayOfWeekToName($day) { if (! is_numeric($day)) { throw new InvalidDayFormatException('The value '' . $day . '' is an ' . 'invalid format for a day of week.'); } if (($day > 6) || ($day < 0)) { throw new InvalidDayOfWeekException('The day number '' . $day . '' is an ' . 'invalid day of the week. Expecting 0-6.'); } $dayNames = array( "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"); return $dayNames[$day]; } echo("The name of the 0 day is: " . convertDayOfWeekToName(0) . "
"); try { echo("The name of the 10 day is: " . convertDayOfWeekToName(10) . "
"); } catch (InvalidDayOfWeekException $e) { echo ("Encountered error while trying to convert value: " . $e->getMessage() . "
"); } try { echo("The name of the 'orange' day is: " . convertDayOfWeekToName('orange') . "
"); } catch (InvalidDayFormatException $e) { echo ("Encountered error while trying to convert value: " . $e->getMessage() . "
"); } ?> 通過檢驗參數(shù)的全法性——這有助于他人使用你需要正確參數(shù)的函數(shù)——你應該檢驗它們 并拋出異常的大意: 盡量拋出接近錯誤的異常. 處理每個特殊的異常. 永遠,永遠不要復制粘貼 把代碼復制到你的編輯里的能力是一把雙刃劍。一方面,它避免了你參照一些示例后重新再打一遍時出現(xiàn)的錯誤;另一方面,它讓書寫相似代碼太簡單了。 你要避免在你的程序應用中復制粘貼代碼。當你發(fā)現(xiàn)自己在這樣做時,停下來并問自己可不可以把復制的部分重復使用。把相同的代碼放在同一個地方可以讓你以后修改時更加的輕松,因為要改變都在一起。 壞習慣:相似的代碼塊 例9表現(xiàn)了除了一些值所在位置之外很相近的幾個方法。有些工具可以檢驗你的代碼中復制粘貼的部分(去看看Resources)。 例9.相似的代碼塊 <?php /** * Counts the number of Messages found in the array of * ResultMessage with the getSeverity() value of "Error" * * @param $messages An array of ResultMessage * @return unknown_type */ function countErrors($messages) { $matchingCount = 0; foreach($messages as $m) { if ($m->getSeverity() == "Error") { $matchingCount++; } } return $matchingCount; } /** * Counts the number of messages found in the array of * ResultMessage with the getSeverity() value of "Warning" * * @param $messages An array of ResultMessage * @return unknown_type */ function countWarnings($messages) { $matchingCount = 0; foreach($messages as $m) { if ($m->getSeverity() == "Warning") { $matchingCount++; } } return $matchingCount; } /** * Counts the number of Messages found in the array of * ResultMessage with the getSeverity() value of "Information" * * @param $messages An array of ResultMessage * @return unknown_type */ function countInformation($messages) { $matchingCount = 0; foreach($messages as $m) { if ($m->getSeverity() == "Information") { $matchingCount++; } } return $matchingCount; } $messages = array(new ResultMessage("Error", "This is an error!"), new ResultMessage("Warning", "This is a warning!"), new ResultMessage("Error", "This is another error!")); $errs = countErrors($messages); echo("There are " . $errs . " errors in the result.
"); ?> 好習慣:可復用的帶參函數(shù) 例10展示了把要復制的代碼入到一個方法中的代碼修改。另一個修改的方法則把工作代理給了一個新的方法。編寫一個通用的方法要花一些時間來設計,當然這會讓你停下來思考,而不是用復制粘貼的組合快捷鍵。但是這樣做會在以后修改時省回第一次多花的時間。 例10.好習慣:可利用的帶參函數(shù) <?php /* * Counts the messages with the given severity in the array * of messages. * * @param $Messages An array of ResultMessage * @return int Count of messages matching $withSeverity */ function countMessages($messages, $withSeverity) { $matchingCount = 0; foreach($messages as $m) { if ($m->getSeverity() == $withSeverity) { $matchingCount++; } } return $matchingCount; } /** * Counts the number of messages found in the array of * ResultMessage with the getSeverity() value of "Error" * * @param $messages An array of ResultMessage * @return unknown_type */ function countErrors($messages) { return countMessages($messages, "Errors"); } /** * Counts the number of messages found in the array of * ResultMessage with the getSeverity() value of "Warning" * * @param $messages An array of ResultMessage * @return unknown_type */ function countWarnings($messages) { return countMessages($messages, "Warning"); } /** * Counts the number of messages found in the array of * ResultMessage with the getSeverity() value of "Warning" * * @param $messages An array of ResultMessage * @return unknown_type */ function countInformation($Messages) { return countMessages($messages, "Information"); } $messages = array(new ResultMessage("Error", "This is an error!"), new ResultMessage("Warning", "This is a warning!"), new ResultMessage("Error", "This is another error!")); $errs = countErrors($messages); echo("There are " . $errs . " errors in the result.
"); ?> 結(jié)論 如果當你開發(fā)PHP的時候養(yǎng)成了本文中提到的好習慣,你寫的代碼將會好讀、好懂、好維護。編寫可維護代碼的方式將讓你的代碼可以高度排錯,并告別低級錯誤。 使用良好命名并用短代碼塊來組強你的代碼會讓你的代碼簡單明了。注明你代碼的目的會讓它的主旨明確易于理解。異常處理讓你的代碼健壯。最后,摒棄復制粘貼的惡習讓你的代碼整潔。
信息發(fā)布:廣州名易軟件有限公司 http://m.jetlc.com
|