天天看點

[譯]Five good programming habits in PHPFive good programming habits in PHP5個PHP程式設計的好習慣

Five good programming habits in PHP

5個PHP程式設計的好習慣

原文位址:http://www.ibm.com/developerworks/opensource/library/os-php-5goodhabits/index.html?ca=dgr-jw64os-php-5goodhabits&S_TACT=105AGY46&S_CMP=GRsitejw64

Depending on whom you ask, the difference between a good developer and an excellent developer, in terms of productivity, is a factor of 10 to 20. An excellent developer is more productive because of his experience and good habits. When poor programming habits sneak into your code, they're a drain on productivity. This article demonstrates some good programming habits that can make you a better programmer.

有些人問,優秀程式員和大牛有什麼差別,大概有10到20種吧。因為大牛有很好的程式設計習慣和豐富的經驗,是以他們非常的高效。如果不好的程式設計習慣出現在你的代碼裡,你的代碼效率就很降低。本文闡述一些好的程式設計習慣,他們可以讓你成為更好的程式員。

In addition to enabling you to build code more productively, these habits can help you build code sustainable for an application's lifetime. Any code you write is likely to spend most of its lifetime in maintenance; application maintenance is a large expense. Establishing good coding habits will enhance design factors like modularity, and your code will be easier to understand and, thus, easier and cheaper to maintain.

這些習慣能讓你的代碼在高效運作的同時提高可維護性。你寫代碼的時候,可能大部分時間都浪費在維護上了,程式的維護代價很高。培養良好的程式設計習慣,如子產品化設計,可以讓你的代碼可讀性更好,進而容易維護。

Bad coding habits seem to accompany defects in code and can cause code to be difficult to change without introducing new defects. The following five good habits, when applied to your PHP code, will help you avoid these pitfalls:

代碼中的問題往往伴随着不良的程式設計習慣,而且後者會導緻代碼不好修改并可能出現新的缺陷。下面有五個好的程式設計習慣,将幫你避免這些陷阱:

  1. Use good naming.
  2. Take smaller bites.
  3. Document your code.
  4. Handle error conditions.
  5. Never, ever, copy and paste.
  1. 使用友好的命名方式。
  2. 使用更精悍短小的代碼。
  3. 注釋你的代碼。
  4. 編寫異常處理。
  5. 永遠,永遠不要複制粘貼.(玉米:我深深的同意這一點)

The next sections explain these habits in detail.

下面的章節将解釋這些習慣。

Use good naming

良好的命名方式

Using good naming is the most important habit because descriptive names make code easier to read and understand. The understandability of your code ultimately determines whether it can be maintained in the future. Even if the code you write contains no comments, if it's easy to understand, it will be much easier for you or someone else to change, if necessary. Your aim, when developing this practice, should be to use good naming to make your code read much like a book.

良好的命名方式是最重要的程式設計習慣,因為好的命名會讓代碼易懂,好懂。代碼的可讀性決定它的可維護性。即使你在代碼沒有寫注釋,如果它可讀性好的話,它也修改起來也會簡單。你應該在練習開時就使用良好的命名方式,讓你的代碼像一本書一樣。

Bad habit: Ambiguous or meaningless names

壞習慣:無意義的難懂的命名

Listing 1 shows code that includes overly short variable names, abbreviations that are difficult to understand, and method names that don't clearly describe what the methods do. Method names that imply the methods do one thing when they really do something else can be particularly problematic because they're misleading.

例1包含一個過短的變量名,寫出這樣的代碼非常不好弄懂,而且函數名也沒有清晰的描述出這個方法是做什麼的。函數名表示了函數的功能,如果它卻是做别的用途的,那就會誤導别人。

Listing 1. Bad: Ambiguous or meaningless names
<?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 . "\n");

?>
      

Good habit: Reflective yet concise names

好習慣:簡單明了的命名

Listing 2 demonstrates code that uses good naming habits. Methods are renamed to be more reflective of what they do and why. Variables are renamed to be more descriptive, as well. The only variable that's left short is

$i

, which in this listing is a looping variable. Although many people may disagree, a short name for the looping variable is acceptable — even good — because it's a clear indicator of functionality.

  例2則給出了使用良好命名方式的代碼。重新命名函數是為了更好的反映它們的功能。變量也重新命名為描述性的。隻有一個在循環中的$i還使用短的變量名。盡管有些人不同意,短變量名在循環中是請允許的——甚至更好些,因為它們清晰的起到了指針的功能。

Listing 2. Good: Reflective yet concise names
<?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 . "\n");

?>
      

You are encouraged to break up large conditions into a method and name the method so it describes the condition. This technique makes the code easier to read and externalizes the condition so it can be abstracted and perhaps even reused. If the terms of the condition change, it's easier to update the method. Because the method has a meaningful name, the code doesn't lose its meaning or become difficult to read.

我鼓勵你在函數中分隔長的條件給函數命名,以便于描述這個條件。(玉米:這句話啥意思?5555)這個技巧會讓你的代碼容易閱讀和擴充,是以它可以被抽象 複用。如果條件發生了改變,這樣也會很容易更新函數 .由于方法有一個見名知義的名字,化碼就不會失去它本來的意思或者變得難以了解。

Back to top

Take smaller bites

使用更少的代碼

It's easy to get focused on solving a problem and start coding away. While you're solving an immediate problem, you keep typing, letting your functions get longer and longer. That's not a problem over the long term, as long as you go back later and refactor the code into smaller bites.

編寫代碼、解決問題是一種容易的事情。當你解決一個正在發生的問題,編呀編,寫呀寫,你的方法越來越長。隻要你回頭使用更少的代碼來重構,就是過了很久也沒什麼問題。

Refactoring is a great idea, but you should develop the habit of writing shorter, more focused methods the first time. Shorter methods that can be viewed in one window are easier to understand. When a method is too long to be viewed all at once in a window, it decreases in understandability because you can't quickly follow its entire flow from beginning to end.

重構是個好主意,但你應該養成第一次就寫出更短小精悍代碼的習慣。在一個視窗上(玉米:不用翻頁)就能看全的短小函數更容易了解。 要是一個函數長出了視窗,就很難了解了,因為你不能快速的從頭到腳的浏覽整個代碼。

When building methods, you should also form the habit of constructing them so they do one thing and one thing only. There are several reasons for such diligent focus in your method writing. First, methods are more easily reused when they do one thing and do it well. Second, such methods are easier to test. Third, such methods are easier to understand and change — if necessary — the simpler they are.

當構思一個方法的時候,你還應該養成一個讓它們隻做一件事情的習慣。以下因素寫代碼時應常注意。第一,隻做一件事情的函數更易于複用。第二,這樣的函數測試更友善。第三,這樣的函數好讀易懂友善改——如果必要的話——讓它們盡可能的簡單吧。

Bad habit: Really long functions (that do a lot)

壞習慣:過長的函數(很多時候)

Listing 3 shows a long function. It's problematic for a couple of other reasons. It does many things, so it isn't cohesive. It will be harder to understand, debug, and test. It iterates through a file and builds a list of entries, it assigns the values to objects, it does some calculations, and more.

例3是過長函數的表現。它不知道自己要做什麼。它做太多的事情,是以沒有內建化。它更難以了解,不好Debug和測試。它周遊檔案建立清單,它給對象指派,它做一些計算,……它耕田,它澆水,甚至做更多事情。(^_^)

Listing 3. Bad: Long functions

  壞習慣:過長函數

<?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>http://www.example.com/feed.xml</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>http://www.example.com/rss</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);

}

?>
      

If you add more to this method, it will soon become virtually unmaintainable.

要是你再加更多東西到這個函數裡,它會很快變得難以維護。

Good habit: Manageable, focused functions

好習慣:可管理,內建化的函數 Listing 4. Good: Manageable, focused functions
<?php

function createRssHeader()
{
    return "<rss version=\"2.0\">" .
        "<channel>" .
        "<title>My Great Feed</title>" .
        "<link>http://www.example.com/feed.xml</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>http://www.example.com/rss</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);
}
?>
      

Breaking down longer methods can offer diminishing returns, so be careful that when introducing this good habit you don't overdo it. It's possible to break up code so much that it's as difficult to read as it was when it was all one monolithic function.

把長函數分割會導緻效率降低,是以要注意,這個好習慣不要使用過度。這樣做可能也會引起閱讀性差,跟原來人家是一個整體時沒什麼差別。

Back to top

Document your code

注釋代碼

Documenting your code well sometimes seems as difficult as writing it in the first place. Knowing what to document is tricky because it's tempting to document what the code is doing. Documenting the code's intention is a better idea. In the header blocks of functions that may not be obvious, tell the reader the expected inputs and outputs of the methods and the original intent.

注釋你的代碼有時就像你剛着手寫代碼一樣困難。明确注釋内容很棘手,因為他要寫出代碼要做什麼。注釋變量是一個好主意。在函數頭部注釋可能不太明顯時,就可以告訴閱讀者函數要什麼參數,有什麼傳回以及主要的意圖。

Documenting what the code is doing is common, but unnecessary. If the code is so confusing that you have to document what it's doing, take that as a hint that you should rewrite the code to make it easier to understand. Develop the habit of using good naming and smaller methods and structures to make your code more readable without having to comment what it does.

通常大家會注釋代碼是做什麼的,但這并不必要。如果代碼讓人困惑以至于你不得不寫注釋說它是做什麼的,這就提示你應該重寫它,使它更好懂。命名良好、更加短小、組織合理的代碼習慣會讓你的代碼用不着注釋就擁有很高的可讀性。

Bad habit: Missing and redundant function documentation

壞習慣:壓根沒有或者叽叽歪歪的函數注釋 (^_^)

The comments in Listing 5 merely tell the reader what the code is doing — that it's iterating through a loop or that it's adding a number. But what is missing is why it's doing what it's doing. It would be difficult for someone maintaining this code to know whether the code can be safely changed without introducing new defects.

例5的注釋隻給出了代碼在做什麼——它的通過循環的周遊、加了個數。但是丢了為什麼這麼做和要做什麼。 這會讓别人難以不影響原代碼的情形下安全修改的做出修改。

Listing 5. Bad: Missing and redundant function documentation

壓根沒胡或者叽叽歪歪的函數注釋

<?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.\n");

?>
      

Good habit: Documented functions and classes

好習慣: 注釋函數和類

The comments in Listing 6 tell the reader the intentions of the classes and methods. The comments tell why the functions are doing what they're doing, which will be much more helpful in the future when the code is being maintained. Conditions may change that require your code to be modified, and that's an easier task if it's simple to find out what your code's purpose was in the first place.

例6裡的注釋标明了類和函數的意圖。注釋表明方法做了什麼和為什麼做,這會對将來了解代碼的意圖很有幫助。環境的變化會需要你進行代碼修改,這就會讓很容易的知道開始時你代碼是做什麼的。

Listing 6. Good: Documented functions and classes

  好習慣:注釋函數和類

<?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 message.
     * @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.\n");

?>
      

Back to top

Handle errors

異常處理

It's been said that when you're writing robust applications, error-handling code seems to follow the 80/20 rule: 80 percent of the code is dedicated to handling exceptions and validations, and 20 percent of the code does the actual work. It's natural when writing code to do happy-path coding. This means writing code that works well for the basic conditions, when all the data is valid and all the conditions are as expected. But such code can be fragile over the application's lifetime. At the other extreme, you may spend too much time writing code for conditions that may never be encountered.

寫健壯應用時經常會提到的異常處理,一般遵循着80/20原則: 80%的代碼用于處理異常或者驗證,20%的代碼沒什麼實際的用途。原始的代碼通常都是在樂觀的環境下編寫的。這意味着代碼可以在資料正常、一切了解的基 礎環境中工作的很好。但是這種代碼在其生命周期内是脆弱的。在極端的情形中,你得花更多的時間來未很可能永遠不會發生的狀況編寫相應代碼。

This habit is about finding the balance between doing enough error handling and not doing so much gold plating that your code is never finished.

這個習慣就是要你處理全部的出錯情況,而且如果要是不這麼做,你的代碼永遠也完不成。

Bad habit: Not handling errors at all

壞習慣:不處理任何異常

The code in Listing 7 demonstrates a couple of bad habits. One is not checking the parameters coming in, even though you know at this point that a parameter in a certain state will cause an exception in your method. The second is that the code calls a method that can throw an exception without handling it. This code will leave the author or maintainer to make guesses about the source of the problem — when problems start occurring.

Listing 7. Bad: Not handling error conditions
<?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) . "\n");
echo("The name of the 10 day is:  " . convertDayOfWeekToName(10) . "\n");
echo("The name of the 'orange' day is:  " . convertDayOfWeekToName('orange') . "\n");

?>
      

Good habit: Programming defensively

好習慣: 防守型程式設計

Listing 8 demonstrates handling and throwing exceptions in a meaningful way. Not only does the additional error handling make the code more robust, but it also helps with readability and understandability. The way the exceptions are handled provides a good indication of what the original author was looking for when the method was written.

例8表明處理并抛出異常是一件很有意義的事情。不隻是額外的異常處理可以讓代碼健壯,但是這有助于提高代碼的可讀性。這種異常處理為原作者檢視何時編寫提供了一個很好的說明。

Listing 8. Good: Programming defensively

  好習慣:防守型程式設計

<?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) . "\n");

try {
    echo("The name of the 10 day is:  " . convertDayOfWeekToName(10) . "\n");
} catch (InvalidDayOfWeekException $e) {
    echo ("Encountered error while trying to convert value:  " . $e->getMessage() . "\n");
}

try {
    echo("The name of the 'orange' day is:  " . convertDayOfWeekToName('orange') . "\n");
} catch (InvalidDayFormatException $e) {
    echo ("Encountered error while trying to convert value:  " . $e->getMessage() . "\n");
}

?>
      

Although checking parameters is validation — and it's helpful to anyone using your functions if you require parameters to be a certain way — you should check them and throw meaningful exceptions:

通過檢驗參數的全法性——這有助于他人使用你需要正确參數的函數——你應該檢驗它們并抛出異常的大意:

  • Handle exceptions as near to the problem as possible.
  • Handle each exception specifically.
  • 盡量抛出接近錯誤的異常.
  • 處理每個特殊的異常.

Back to top

Never, ever copy and paste

永遠,永遠不要複制粘貼

The ability to copy code from one place and paste it into your code editor is a double-edged sword. On one hand, it saves a lot of errors when you're retyping from an example or a template. On the other hand, it makes proliferation of similar code way too easy.

把代碼複制到你的編輯裡的能力是一把雙刃劍。一方面,它避免了你參照一些示例後重新再打一遍時出現的錯誤;另一方面,它讓書寫相似代碼太簡單了。

Be on your guard against copying and pasting code between parts of your application. When you find yourself doing it, stop and ask yourself how you could rewrite the section of code you're copying to be something that you can reuse. Putting code in one place allows you to more easily maintain your code, to a large degree, because changes need to be made in only one place.

你要避免在你的程式應用中複制粘貼代碼。當你發現自己在這樣做時,停下來并問自己可不可以把複制的部分重複使用。把相同的代碼放在同一個地方可以讓你以後修改時更加的輕松,因為要改變都在一起。

Bad habit: Similar sections of code

壞習慣:相似的代碼塊

Listing 9 shows a couple of methods that are nearly identical, except for a couple of values here and there. Tools are available to help you find copied and pasted code (see Resources).

例9表現了除了一些值所在位置之外很相近的幾個方法。有些工具可以檢驗你的代碼中複制粘貼的部分(去看看Resources)。

Listing 9. Bad: Similar sections of code  相似的代碼塊
<?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.\n");
?>
      

Good habit: Reusable functions with parameters

好習慣:可複用的帶參函數

Listing 10 shows the code modified to put the copied code into one method. The other methods have been changed to delegate the work to the new method. Building the common method takes some design time, and certainly doing so makes you pause and think instead of instinctively using the copy-and-paste shortcut key combinations. But you'll get back the time you invested the first time the common code needs to be changed.

例10展示了把要複制的代碼入到一個方法中的代碼修改。另一個修改的方法則把工作代理給了一個新的方法 。編寫一個通用的方法要花一些時間來設計,當然這會讓你停下來思考,而不是用複制粘貼的組合快捷鍵。但是這樣做會在以後修改時省回第一次多花的時間。

Listing 10. Good: Reusable functions with parameters

好習慣 :可利用的帶參函數

<?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.\n");

?>
      

Back to top

Conclusion

If you develop the good habits discussed in this article while developing your PHP code, you'll build code that is easy to read, understand, and maintain. Building easily maintainable code in this manner will enable you to debug, fix, and extend your code with lower risk.

Using good naming and organizing your code into smaller prices makes your code easier to read. Documenting the purpose of your code makes its intent easier to understand and extend. Handling errors properly makes your code more robust. Finally, breaking the crutch of copying and pasting lets you keep your code clean.

結論

如果當你開發PHP的時候養成了本文中提到的好習慣,你寫的代碼将會好讀、好懂、好維護。編寫可維護代碼的方式将讓你的代碼可以高度排錯,并告别低級錯誤。

使用良好命名并用短代碼塊來組強你的代碼會讓你的代碼簡單明了。注明你代碼的目的會讓它的主旨明确易于了解。異常處理讓你的代碼健壯。最後,摒棄複制粘貼的惡習讓你的代碼整潔。

-----------------------------------------------------

玉米寄語:最後的這個複制粘貼的建議讓我一身冷汗,想想其實有很多代碼都是重複的工作,有時隻是為了“快”,而把相似的代碼又“複制”了一遍,雖然我沒有使用ctrl+c\v 但是也是寫了很多類似的代碼,看來,review的事兒可以在世界和平的事兒之前考慮了。