Năm thói quen lập trình tốt trong PHP

Các thói quen giúp cho mã PHP của bạn dễ đọc và bảo trì

Giống như bất kỳ ngôn ngữ nào, các nhà phát triển có thể viết mã PHP với chất lượng từ rất tồi tệ đến rất tốt. Tìm hiểu các thói quen lập chương trình tốt có thể giúp bạn vượt qua khoảng cách về năng suất.

Nathan A. Good, Kỹ sư trưởng, tư vấn, Freelance Developer

Nathan Good sống tại vùng Twin Cities của bang Minnesota. Về chuyên môn, ông làm công việc phát triển phần mềm, kiến trúc phần mềm và quản trị các hệ thống. Khi ông không viết phần mềm, ông rất thích xây dựng các máy chủ và máy tính cá nhân, đọc và làm việc với các công nghệ mới và cố gắng khuyến khích bạn bè của mình chuyển sang phần mềm mã nguồn mở


Cấp độ đóng góp cho developerWorks của
        tác giả

12 06 2009

Tùy thuộc vào người mà bạn hỏi, sự khác biệt giữa một nhà phát triển tốt và một nhà phát triển xuất sắc, về mặt năng xuất, là một thừa số từ 10 đến 20 lần. Một nhà phát triển xuất sắc có năng suất cao hơn do anh ta có kinh nghiệm và các thói quen tốt. Khi các thói quen lập chương trình kém luồn lách vào trong mã của bạn, chúng sẽ bòn rút hết năng suất. Bài viết này chứng tỏ một số thói quen lập chương trình tốt có thể giúp bạn trở thành một lập trình viên tốt hơn.

Ngoài việc cho phép bạn để xây dựng mã năng suất hơn, những thói quen này có thể giúp bạn xây dựng mã bền vững cho suốt cuộc đời của ứng dụng. Bất cứ mã nào mà bạn viết ra nhiều khả năng là hầu hết cuộc đời của nó sẽ trải qua khâu bảo trì; việc bảo trì ứng dụng có chi phí lớn. Việc tạo ra các thói quen mã hóa tốt sẽ nâng cao các nhân tố thiết kế như khả năng lắp ghép mô đun và mã của bạn sẽ dễ hiểu hơn và do đó bảo trì dễ dàng và có chi phí rẻ hơn.

Các thói quen mã hóa xấu dường như luôn đi kèm các nhược điểm trong mã và có thể làm cho mã khó thay đổi mà không sinh thêm ra các khiếm khuyết mới. Dưới đây là năm thói quen tốt, khi áp dụng vào mã PHP của bạn, sẽ giúp bạn tránh được các cạm bẫy này:

  1. Chọn các tên thích hợp.
  2. Làm từng mẩu nhỏ hơn.
  3. Viết chú giải mã của bạn.
  4. Xử lý các điều kiện lỗi.
  5. Không bao giờ sao chép và dán liên tục.

Phần tiếp theo giải thích chi tiết về những thói quen này.

Chọn các tên thích hợp

Chọn các tên thích hợp là thói quen quan trọng nhất vì các tên mô tả làm cho mã dễ đọc và dễ hiểu hơn. Tính dễ hiểu của mã của bạn quyết định việc nó có thể bảo trì được trong tương lai hay không. Ngay cả khi mã bạn viết không chứa bất kỳ chú giải nào, nếu nó dễ hiểu, sẽ dễ dàng hơn cho bạn hay một người nào khác thay đổi khi cần thiết. Mục đích của bạn, khi tập thói quen này, sẽ là chọn cách đặt tên tốt để làm cho việc đọc mã của bạn giống như đọc một quyển sách.

Thói quen xấu: Các tên không có nghĩa hay nhập nhằng

Liệt kê 1 hiển thị mã có các tên biến ngắn quá mức, các chữ viết tắt là rất khó hiểu và các tên phương thức không mô tả rõ ràng những gì mà các phương thức làm. Các tên phương thức ngụ ý các phương thức thực hiện một việc, trong khi thực sự chúng lại làm một cái gì đó khác, có thể đặc biệt rắc rối do chúng gây nhầm lẫn.

Liệt kê 1. Thói quen xấu: Các tên không có nghĩa hay nhập nhằng
<?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");

?>

Thói quen tốt: Các tên phản ánh mà cô đọng

Liệt kê 2 biểu thị mã áp dụng thói quen đặt tên tốt. Các phương thức được đổi tên để phản ánh đúng hơn về chúng sẽ làm gì và tại sao chúng làm như vậy. Các biến cũng được đổi tên để diễn tả hơn. Một biến duy nhất rất ngắn là $i, trong liệt kê này là một biến vòng lặp. Mặc dù nhiều người có thể không đồng ý, một tên ngắn cho biến vòng lặp là có thể chấp nhận được — thậm chí là tốt — bởi vì nó là một chỉ báo rõ ràng về chức năng.

Liệt kê 2. Thói quen tốt: Các tên phản ánh mà cô đọng
<?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");

?>

Bạn được khuyến khích phân nhỏ các điều kiện lớn thành một phương thức và đặt tên phương thức sao cho nó mô tả một điều kiện. Kỹ thuật này làm cho mã dễ đọc hơn và biểu lộ ra ngoài (externalize) một điều kiện sao cho nó có thể được trừu tượng hóa và thậm chí còn tái sử dụng được. Nếu các khoản trong điều kiện thay đổi, thì cũng dễ dàng cập nhật phương thức hơn. Bởi vì phương thức có một tên có ý nghĩa, nên mã không bị mất đi ý nghĩa của nó hoặc sẽ trở thành khó đọc.


Làm từng mẩu nhỏ hơn

Rất dễ dàng tập trung ngay vào việc giải quyết một vấn đề và bắt đầu viết mã ngay. Trong khi bạn đang giải quyết một vấn đề trước mắt, bạn liên tục gõ vào, làm cho các hàm của bạn càng ngày càng dài ra. Về lâu dài đây không phải là một vấn đề, miễn là sau đó bạn quay lại và cấu trúc lại mã thành các đoạn nhỏ hơn.

Cấu trúc lại mã là một ý tưởng tuyệt vời, nhưng bạn nên tập thói quen viết các phương thức ngắn hơn, tập trung hơn ngay từ đầu. Các phương thức ngắn hơn có thể được xem trong một cửa sổ sẽ dễ hiểu hơn. Khi một phương thức quá dài, không thể xem tất cả cùng một lúc trong một cửa sổ, nó sẽ làm giảm tính dễ hiểu bởi vì bạn không thể nhanh chóng theo dõi toàn bộ dòng chảy của nó từ đầu đến cuối.

Khi xây dựng các phương thức, bạn cũng nên tạo thói quen xây dựng chúng sao cho chúng làm một việc và chỉ một việc mà thôi. Có một số lý do cho việc tập trung cao độ như vậy khi viết phương thức của bạn. Trước tiên, các phương thức được tái sử dụng một cách dễ dàng hơn khi chúng chỉ làm một việc và làm tốt việc đó. Thứ hai, các phương thức như vậy dễ dàng thử nghiệm hơn. Thứ ba, các phương thức như vậy càng dễ hiểu và dễ thay đổi hơn — nếu cần thiết — khi chúng càng đơn giản hơn.

Thói quen xấu: Các hàm dài thực sự (làm nhiều việc)

Liệt kê 3 cho thấy một hàm dài. Nó rắc rối vì nhiều lẽ khác. Nó làm nhiều việc, do đó nó sẽ không gắn kết chặt chẽ. Nó sẽ khó hiểu, khó gỡ rối và khó thử nghiệm hơn. Nó kéo dài suốt một tệp tin và xây dựng một danh sách các mục, nó gán các giá trị cho các đối tượng, nó thực hiện một số phép tính toán và nhiều hơn nữa.

Liệt kê 3. Thói quen xấu: Các hàm dài
<?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>editor@example.com</managingEditor>" .
        "<webMaster>webmaster@example.com</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);

}

?>

Nếu bạn thêm nhiều hơn nữa vào phương thức này, nó sẽ sớm trở nên hầu như không thể bảo trì được.

Thói quen tốt: Các hàm tập trung, quản lý được

Liệt kê 4 biểu thị một cách viết lại phương thức gốc để cho dễ đọc hơn và cô đọng hơn. Trong ví dụ này, phương thức dài đã được phân thành các phương thức nhỏ hơn mà mỗi phương thức làm một việc và làm tốt việc đó. Kết quả sẽ là khả năng sử dụng lại tốt hơn trong tương lai và sẽ dễ dàng thử nghiệm hơn.

Liệt kê 4. Thói quen tốt: Các hàm tập trung, quản lý được
<?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>editor@example.com</managingEditor>" .
        "<webMaster>webmaster@example.com</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);
}
?>

Việc phân nhỏ các phương thức dài cũng có thể dẫn đến sự suy giảm trở lại, vì vậy hãy cẩn thận, khi tập thói quen tốt này, đừng lạm dụng làm quá lên. Rất có thể việc chia tách mã nhiều đến mức làm nó cũng khó đọc như khi tất cả còn là một hàm nguyên khối.


Viết chú giải mã của bạn

Việc chú giải mã của bạn, thoạt đầu đôi khi có vẻ cũng khó khăn như việc viết mã. Biết phải chú giải những gì đòi hỏi phải khéo léo vì rất dễ bị lôi kéo thành chú giải những gì mà mã đang làm. Một ý tưởng tốt hơn là chú giải mục đích của mã là gì. Trong các khối đầu đề của hàm, khi mà mục đích của hàm có thể còn chưa hiển nhiên, hãy nói cho người đọc biết các đầu vào và các đầu ra của các phương thức là gì và mục đích nguyên thủy của nó.

Việc chú giải mã đang làm gì là rất phổ biến, nhưng không cần thiết. Nếu mã lộn xộn đến mức mà bạn phải ghi chú nó đang làm gì, hãy coi đây như là một gợi ý rằng bạn nên viết lại mã để làm cho nó dễ hiểu hơn. Hãy tập thói quen chọn đặt tên thích hợp, dùng các phương thức và các cấu trúc nhỏ hơn để làm cho mã của bạn dễ đọc hơn mà không phải chú giải nó làm gì.

Thói quen xấu: Chú giải hàm thiếu và thừa

Các chú giải trong Liệt kê 5 chỉ nói cho người đọc mã đang làm gì — đó là việc lặp lại thông qua một vòng lặp hay nó thêm một số. Nhưng cái đang thiếu là lý do tại sao nó đang làm những gì nó làm. Sẽ khó khăn cho ai đó đang bảo trì mã này nếu muốn biết mã có thể được thay đổi an toàn mà không đưa thêm vào các nhược điểm mới hay không.

Liệt kê 5. Thói quen xấu: Chú giải hàm thiếu và thừa
<?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");

?>

Thói quen tốt: Các hàm và các lớp có chú giải

Các chú giải trong Liệt kê 6 thông báo cho người đọc mục đích của các lớp và các phương thức. Các chú giải này cho biết lý do tại sao các hàm đang làm những gì mà chúng đang làm, sẽ có ích nhiều hơn trong tương lai khi mã được bảo trì. Các điều kiện có thể thay đổi và đòi hỏi mã của bạn phải được sửa đổi, và đó sẽ là một nhiệm vụ dễ dàng hơn nếu có thể nhanh chóng tìm ra mục đích mã của bạn đã là gì khi bắt đầu.

Liệt kê 6. Thói quen tốt: Các hàm và các lớp có chú giải
<?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");

?>

Xử lý các lỗi

Người ta đã nói rằng khi bạn viết các ứng dụng chắc chắn, mã xử lý lỗi dường như tuân theo quy luật 80/20: 80 phần trăm mã dành cho xử lý các trường hợp ngoại lệ và kiểm tra hợp lệ, và 20 phần trăm mã thực tế làm công việc. Viết mã để làm cho việc mã hóa đi theo tuyến đường may mắn (happy-path coding) là thói quen khá tự nhiên. Điều này có nghĩa là viết mã hoạt động tốt cho các điều kiện cơ sở, khi tất cả các dữ liệu là hợp lệ và tất cả các điều kiện đúng như mong đợi. Tuy nhiên, mã như vậy có thể dễ hỏng trong cuộc đời của ứng dụng. Ở cực khác, bạn có thể dành quá nhiều thời gian viết mã cho các điều kiện mà có thể không bao giờ gặp phải.

Thói quen này là về việc tìm sự cân bằng giữa thực hiện xử lý lỗi đúng mức và không thực hiện mạ vàng nhiều tới mức mà mã của bạn sẽ không bao giờ được hoàn tất.

Thói quen xấu: Hoàn toàn không xử lý lỗi

Các mã trong Liệt kê 7 biểu thị một số thói quen xấu. Thói quen xấu thứ nhất là không kiểm tra các thông số đưa vào, mặc dù bạn biết vào thời điểm này một tham số trong một trạng thái nhất định sẽ gây ra một ngoại lệ trong phương thức của bạn. Thói quen xấu thứ hai là các mã gọi ra một phương thức có thể đưa ra một ngoại lệ mà không xử lý nó. Mã này sẽ để mặc tác giả hoặc người bảo trì đoán mò về nguồn gốc của vấn đề — khi các vấn đề bắt đầu xảy ra.

Liệt kê 7. Thói quen xấu: Không xử lý các điều kiện lỗi
<?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");

?>

Thói quen tốt: Lập trình có tính phòng vệ tốt

Liệt kê 8 biểu thị việc xử lý và đưa ra các ngoại lệ một cách có ý nghĩa. Không chỉ thực hiện xử lý lỗi bổ sung để làm cho mã vững chãi hơn, mà còn trợ giúp cho tính dễ đọc và dễ hiểu hơn. Cách thức xử lý các ngoại lệ cung cấp một chỉ báo tốt về cái mà tác giả ban đầu tìm kiếm khi viết phương thức này.

Liệt kê 8. Thói quen tốt: Lập trình có tính phòng vệ tốt
<?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");
}

?>

Mặc dù việc kiểm tra các thông số là xác nhận hợp lệ — và sẽ có ích cho bất kỳ ai khi sử dụng các hàm của bạn nếu bạn yêu cầu các tham số theo một cách nhất định — bạn nên kiểm tra chúng và đưa ra các ngoại lệ có ý nghĩa:

  • Xử lý các ngoại lệ càng gần nơi xảy ra vấn đề càng tốt.
  • Xử lý cụ thể từng ngoại lệ.

Không bao giờ liên tục sao chép và dán

Khả năng sao chép mã từ một nơi và dán nó vào trong trình soạn thảo mã của bạn là một con dao hai lưỡi. Một mặt, nó tránh được rất nhiều lỗi khi bạn đang gõ lại từ một ví dụ hoặc một bản mẫu. Mặt khác, nó làm lây lan nhanh cách viết mã giống nhau quá dễ dàng.

Hãy cảnh giác chống lại việc sao chép và dán mã giữa các phần của ứng dụng của bạn. Khi bạn thấy mình đang làm điều đó, hãy dừng lại và tự hỏi, làm thế nào để có thể viết lại phần mã mà bạn đang sao chép để thành một cái gì đó có thể tái sử dụng. Đặt mã vào chỉ một nơi cho phép bạn bảo trì mã của mình một cách dễ dàng hơn, ở một mức độ lớn, bởi vì các thay đổi cần được thực hiện chỉ ở một nơi thôi.

Thói quen xấu: Các phần mã giống nhau

Liệt kê 9 hiển thị một cặp phương thức gần giống hệt nhau, ngoại trừ một vài giá trị ở đâu đó. Có sẵn các công cụ để giúp bạn tìm thấy các mã được sao chép và dán (xem Tài nguyên).

Liệt kê 9. Thói quen xấu: Các phần mã giống nhau
<?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");
?>

Thói quen tốt: Các hàm sử dụng lại được với các tham số

Liệt kê 10 hiển thị mã được sửa đổi để đặt phần mã được sao chép vào trong một phương thức. Các phương thức khác đã được thay đổi để chuyển giao công việc cho phương thức mới này. Việc xây dựng phương thức chung cần một số thời gian thiết kế và chắc chắn làm như vậy sẽ làm cho bạn tạm dừng và suy nghĩ thay vì theo bản năng sử dụng các kết hợp phím tắt sao chép-và-dán. Nhưng bạn sẽ được bù lại khoảng thời gian mà bạn đã đầu tư ngay khi phần mã chung cần phải được thay đổi lần đầu tiên.

Liệt kê 10. Thói quen tốt: Các hàm sử dụng lại được với các tham số
<?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");

?>

Kết luận

Nếu bạn tập các thói quen tốt đã thảo luận trong bài viết này trong khi đang phát triển mã PHP của bạn, bạn sẽ xây dựng mã dễ đọc, hiểu và bảo trì. Việc xây dựng một mã bảo trì dễ dàng theo cách này sẽ cho phép bạn gỡ lỗi, sửa chữa và mở rộng mã của bạn với mức rủi ro thấp hơn.

Việc chọn đặt tên thích hợp và tổ chức mã của bạn thành các đoạn nhỏ hơn làm cho mã của bạn dễ đọc hơn. Việc chú giải mục đích của mã của bạn làm cho mục đích của nó dễ hiểu và mở rộng hơn. Việc xử lý đúng đắn các lỗi làm mã của bạn vững chãi hơn. Cuối cùng, việc từ bỏ cái nạng sao chép và dán cho phép bạn giữ sạch mã của mình.

Tài nguyên

Học tập

  • Đọc "Build seven good object-oriented habits in PHP" để bắt đầu chuyển tiếp từ lập trình theo thủ tục sang lập trình hướng-đối tượng.
  • Đọc Code Complete của Steven C. McConnell để tìm hiểu thêm về cách viết mã có chất lượng cao.
  • Tìm hiểu về "Advanced PHP V5 objects" để xây dựng mã PHP có thể sử dụng lại.
  • Đọc về "Five common PHP design patterns" để tìm hiểu làm thế nào để áp dụng các mẫu thiết kế hướng-đối tượng trong PHP.
  • Đọc về "Five more PHP design patterns" để học cách làm thế nào để áp dụng nhiều mẫu thiết kế hướng-đối tượng hơn trong PHP.
  • Trong phần Architecture zone trên developerWorks, nhận các tài nguyên mà bạn cần để nâng cao kỹ năng của bạn trong vũ đài kiến trúc.
  • PHP.net là tài nguyên trung tâm cho các nhà phát triển PHP.
  • Xem "Danh sách khuyến khích đọc PHP."
  • Duyệt qua tất cả các nội dung PHP trên developerWorks.
  • Mở rộng các kỹ năng của bạn bằng cách xem các tài nguyên dự án PHP của developerWorks của IBM.
  • Để nghe phỏng vấn và các cuộc thảo luận thú vị dành cho các nhà phát triển phần mềm, hãy xem developerWorks podcasts.
  • Bạn cần sử dụng một cơ sở dữ liệu với PHP? Xem Zend Core for IBM, một môi trường phát triển và sản xuất PHP dễ cài đặt, trơn tru, có sẵn để dùng ngay, có hỗ trợ IBM DB2 V9.
  • Theo dõi sát các sự kiện kỹ thuật và webcasts của developerWorks.
  • Xem các hội nghị sắp tới, các cuộc triển lãm thương mại, webcasts và các sự kiện khác trên khắp thế giới đang được các nhà phát triển mã nguồn mở của IBM quan tâm đến.
  • Truy cập vào Vùng mã nguồn mở của developerWorks để cập nhật rất nhiều dự án, các công cụ và các thông tin hướng dẫn để giúp bạn phát triển với các công nghệ mã nguồn mở và sử dụng chúng với các sản phẩm của IBM.
  • Theo dõi và tìm hiểu về các công nghệ mã nguồn mở và IBM và các chức năng sản phẩm với các trình diễn mẫu theo yêu cầu miễn phí của developerWorks.

Lấy sản phẩm và công nghệ

  • Đổi mới dự án phát triển mã nguồn mở tiếp theo của bạn với phần mềm dùng thử của IBM, có sẵn để tải về hoặc trên đĩa DVD.
  • Tải về các phiên bản đánh giá sản phẩm IBM và nhận các sản phẩm phần mềm trung gian và các công cụ phát triển ứng dụng thực hành từ DB2®, Lotus®, Rational®, Tivoli® và WebSphere®.

Thảo luận

Bình luận

developerWorks: Đăng nhập

Các trường được đánh dấu hoa thị là bắt buộc (*).


Bạn cần một ID của IBM?
Bạn quên định danh?


Bạn quên mật khẩu?
Đổi mật khẩu

Bằng việc nhấn Gửi, bạn đã đồng ý với các điều khoản sử dụng developerWorks Điều khoản sử dụng.

 


Ở lần bạn đăng nhập đầu tiên vào trang developerWorks, một hồ sơ cá nhân của bạn được tạo ra. Thông tin trong bản hồ sơ này (tên bạn, nước/vùng lãnh thổ, và tên cơ quan) sẽ được trưng ra cho mọi người và sẽ đi cùng các nội dung mà bạn đăng, trừ khi bạn chọn việc ẩn tên cơ quan của bạn. Bạn có thể cập nhật tài khoản trên trang IBM bất cứ khi nào.

Thông tin gửi đi được đảm bảo an toàn.

Chọn tên hiển thị của bạn



Lần đầu tiên bạn đăng nhập vào trang developerWorks, một bản trích ngang được tạo ra cho bạn, bạn cần phải chọn một tên để hiển thị. Tên hiển thị của bạn sẽ đi kèm theo các nội dung mà bạn đăng tải trên developerWorks.

Tên hiển thị cần có từ 3 đến 30 ký tự. Tên xuất hiện của bạn phải là duy nhất trên trang Cộng đồng developerWorks và vì lí do an ninh nó không phải là địa chỉ email của bạn.

Các trường được đánh dấu hoa thị là bắt buộc (*).

(Tên hiển thị cần có từ 3 đến 30 ký tự)

Bằng việc nhấn Gửi, bạn đã đồng ý với các điều khoản sử dụng developerWorks Điều khoản sử dụng.

 


Thông tin gửi đi được đảm bảo an toàn.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=70
Zone=Nguồn mở
ArticleID=396429
ArticleTitle=Năm thói quen lập trình tốt trong PHP
publish-date=06122009