PHP プログラミングのための 5 つの良い習慣を身につける

PHP コードを読みやすく、管理しやすくするための習慣

他の言語の場合とまったく同じように、開発者が PHP で作成するコードの品質は、恐ろしいほどひどいものから非常に素晴らしいものまで非常に幅があります。そうした生産性のギャップを埋めるために役立つ、良いプログラミング習慣を学びましょう。

Nathan A. Good (mail@nathanagood.com), Senior Information Engineer, Freelance Developer

Nathan A. Good lives in the Twin Cities area of Minnesota. Professionally, he does software development, software architecture, and systems administration. When he's not writing software, he enjoys building PCs and servers, reading about and working with new technologies, and trying to get his friends to make the move to open source software. He's written and co-written many books and articles, including Professional Red Hat Enterprise Linux 3, Regular Expression Recipes: A Problem-Solution Approach and Foundations of PEAR: Rapid PHP Development.



2008年 12月 02日

質問する相手にもよりますが、満足できるレベルの開発者と非常に優れた開発者との間の生産性の違いは 10 倍から 20 倍もあります。素晴らしい開発者の生産性が高い理由は、彼らが経験豊富であり、また良い習慣を身に付けているためです。良くないプログラミング習慣がコードの中に入り込むと、生産性を阻害します。この記事では、皆さんをより優れたプログラマーにするための良い習慣をいくつか紹介します。

これらの習慣を身に付けることで、コードを作成する作業の生産性を高められるだけではなく、アプリケーションの全存続期間にわたって維持可能なコードを作成できるようになります。皆さんがどのようなコードを作成するにせよ、おそらくそのコードの存続期間の大部分は保守作業に当てられます。つまりアプリケーションの保守は大きなコスト要因なのです。良いコーディング習慣を身に付けることで、例えばモジュール性の高い設計ができるなど、優れた設計ができるようになると同時に、コードは理解しやすく、保守も容易かつ安価に行えるようになります。

悪いコーディング習慣を身に付けてしまうと、コードに欠陥が生じがちであり、コードを変更する際にも新たな欠陥が生じる可能性が非常に高くなります。PHP のコードに次の 5 つの良い習慣を適用すると、そうした問題を回避できるようになります。

  1. 適切な名前を使う
  2. 小さく分割する
  3. コードをドキュメント化する
  4. エラー条件を処理する
  5. 決してコピー・アンド・ペーストをしない

以下のセクションでは、これらの習慣を詳細に説明します。

適切な名前を使う

適切な名前を使うことは最も重要な習慣です。名前がわかりやすければコードが読みやすく、理解しやすくなるからです。コードが理解しやすいかどうかは結局のところ、そのコードを将来保守できるかどうかを左右します。たとえ皆さんが作成するコードにコメントが何も含まれていないとしても、そのコードが理解しやすければ、皆さんや他の誰かが必要に応じて変更を行う際にも作業を行いやすくなります。この習慣を身に付けるために目指すべきことは、コードが本のように読みやすくなるように、適切な名前を使うことです。

悪い習慣: 曖昧な名前、または無意味な名前

リスト 1 に示すコードには、短すぎる変数名や理解しにくい短縮名、動作を明確に表現していないメソッド名が含まれています。メソッド名から連想される動作と実際の動作が異なると誤解を生じやすいため、特に問題が起こりがちです。

リスト 1. 悪い習慣: 曖昧な、または無意味な名前
<?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");

?>

適切な習慣: 動作を反映した簡潔な名前

リスト 2 は適切な名前を付ける良い習慣に従って作成したコードです。メソッド名は、これらのメソッドが何をし、なぜそうするのかを反映した名前に変更されています。また変数名も、その変数の役割を説明した名前に変更されています。唯一、短いままの変数は $i (このリストではループ変数) です。同意しない人が多いかもしれませんが、ループ変数の名前が短いことは妥当なことであり、むしろ適切でさえあります。名前が短いことで、ループ変数の機能を明確に示すことができるからです。

リスト 2. 適切な習慣: 動作を反映した簡潔な名前
<?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");

?>

また、規模の大きな条件はメソッドに分割し、その条件を表す名前をそのメソッドに付けることが推奨されます。この手法によってコードが読みやすくなり、条件を外部化できるため、コードを抽象化することができ、さらには再利用もできるかもしれません。条件の項目が変更された場合にも、そのメソッドを容易に更新することができます。メソッドの名前は意味のわかるものであるため、コードの意味がわかりにくくなったりコードが読みにくくなったりすることがありません。


小さく分割する

よくあることですが、問題の解決のみに焦点を絞り、すぐにコーディングを始めてしまいがちです。当座の問題を解決しようとする間に入力を続ける結果、関数はどんどん長くなります。後から戻って、小さな単位にコードをリファクタリングするのであれば、そうしたコーディング方法が長期にわたる問題にはなることはありません。

リファクタリングは素晴らしい考えですが、簡潔で焦点を絞ったメソッドを最初に作成する習慣を身に付けるべきなのです。1 画面に収まるような簡潔なメソッドならば、容易に理解することができます。メソッドが長すぎ、1 つの画面にすべてを一度に表示することができないと、そのメソッドの全体の流れを最初から最後まで素早く追うことができないため、そのメソッドを理解しにくくなります。

また、メソッドを作成する場合には、そのメソッドが 1 つのことのみを行うように作成する習慣も身に付ける必要があります。なぜ厳密に焦点を絞ってメソッドを作成する必要があるのか、その理由はいくつかあります。第 1 に、1 つのことを適切に行うメソッドであれば、再利用が容易になります。第 2 に、そのようなメソッドはテストが容易です。第 3 に、そうしたメソッドは、単純であればあるほど理解しやすく、また変更が必要になったとしても変更が容易です。

悪い習慣: 非常に長い (そして多くのことをする) 関数

リスト 3 は長い関数を示しています。この関数には他にもいくつか問題があります。この関数は多くのことを行うため、焦点が曖昧です。この関数は理解しにくく、またデバッグやテストが困難です。この関数はファイルに繰り返し処理を行ってエントリーのリストを作成し、オブジェクトに値を割り当て、いくつかの計算を行い、さらに他のこともします。

リスト3. 悪い習慣: 長い関数
<?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);

}

?>

リスト 3 にさらなる処理を追加すると、このメソッドはすぐに、ほとんどメンテナンス不能になります。

良い習慣: 管理しやすい、焦点を絞った関数

リスト 4 は、元のメソッドを作成し直し、もっと簡潔に読みやすくしたものです。この例では、長いメソッドは小さなメソッドに分割され、それぞれの小さなメソッドが 1 つのことを適切に行います。その結果、将来、再利用がしやすくなり、またテストも容易になります。

リスト 4. 良い習慣: 管理しやすい、焦点を絞った関数
<?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);
}
?>

長いメソッドを分割していっても効果は次第に弱まるため、この良い習慣を適用する際には過度にならないように注意する必要があります。コードを分割しすぎた結果、すべてが一体であった関数と同じように読みにくくなることもあり得るのです。


コードをドキュメント化する

コードを適切にドキュメント化することは、そもそもそのコードを作成するのと同じくらい困難に思えることがあります。何をドキュメント化するのかという判断は難しく、コードで行っている内容をドキュメント化してしまいがちですが、適切なのはコードの目的をドキュメント化することです。一目瞭然ではないような関数のヘッダー・ブロックの中で、そのメソッドで想定される入力と出力、そして本来の目的を、読む人に対して伝えるのです。

コードが何をしているのかをドキュメント化することは一般的ですが、必要なことではありません。コードがわかりにくいためコードの動作をドキュメント化しなければならないとしたら、それをヒントと考え、理解しやすいようにコードを作成し直すべきなのです。適切な名前を使い、簡潔なメソッドや構造を使う習慣を身に付ければ、コードの動作にコメントを付けなくてもコードは読みやすくなります。

悪い習慣: 関数がドキュメント化されておらず、ドキュメント化されていても冗長である

リスト 5 のコメントは、単にコードの動作 (ループを繰り返し処理していることや、ある数値を加算している、など) を読む人に伝えているにすぎず、コードがそうした動作をする理由を説明していません。このコードを保守する人が、新たな欠陥を生ずることなくコードを安全に変更できるかどうかを判断することは困難です。

リスト 5. 悪い習慣: 関数がドキュメント化されておらず、ドキュメント化されていても冗長である
<?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");

?>

良い習慣: 関数とクラスをドキュメント化する

リスト 6 のコメントは読む人に対して、クラスとメソッドの目的を伝えるとともに、関数がなぜそのような動作をするかを伝えており、将来コードの保守をする際には単に動作を記述したコメントよりも遥かに役立ちます。条件は変更されるかもしれず、それによってコードの変更が必要になるかもしれませんが、コードの目的が最初から理解しやすければ変更は容易なものです。

リスト 6. 良い習慣: 関数とクラスをドキュメント化する
<?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");

?>

エラーを処理する

堅牢なアプリケーションを作成しようとする場合、エラー処理のコードは 80/20 ルールに従うと言われています。つまり 80 パーセントのコードは例外と検証の処理に費やされ、実際にエラー処理を行うのはコードの 20 パーセントだというのです。コードを作成する際に「幸運な場合のためのコーディング」をしてしまうのは自然なことです。「幸運な場合のためのコーディング」ということは、基本的な条件 (すべてのデータが有効であり、すべての条件が想定どおりの場合) に対して適切に動作するコードのみを作成してしまう、ということです。しかしそうしたコードはアプリケーションの存続期間全体をとおして考えると脆弱です。またもう一方の極端な場合として、決して起こりえない条件のためのコード作成に時間をかけすぎてしまうこともあるかもしれません。

この習慣の要点は、十分なエラー処理を行うことと、コードが永遠に完成しないほど完璧なエラー処理を行うこととの間で妥協点を見つけるということです。

悪い習慣: エラー処理をまったく行わない

リスト 7 のコードは、いくつかの悪い習慣を示しています。第 1 に悪い点は、入力されるパラメーターをチェックしていないことです (この時点でパラメーターの状態によってはメソッドに例外が発生することがわかっているにもかかわらず、チェックをしていません)。第 2 に悪い点は、このコードは例外をスローする可能性のあるメソッドを呼び出していますが、その例外を処理していません。このコードで問題が起こり始めると、このコードの作成者や保守をする人が問題の原因を推測しなければならない羽目になります。

リスト 7. 悪い習慣: エラー条件を処理しない
<?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");

?>

良い習慣: 問題発生時を考えたプログラミングをする

リスト 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) . "\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");
}

?>

パラメーターのチェックでは妥当性の検証を行っていますが、パラメーターが必ず特定の状態になるようにすると、その関数を使う人にとって役立つものですが、パラメーターのチェックを行った上で次のように意味のある例外をスローする必要があります。

  • 可能な限り問題の核心に迫れるように例外を処理する
  • それぞれの例外を個別に処理する

決してコピー・アンド・ペーストをしない

1 つの場所からコード・エディターにコードをコピー・アンド・ペーストできる機能は両刃の剣です。この機能は、サンプルやテンプレートの内容をタイプし直す際の大量のエラーを防ぐことができる一方で、似たようなコードを安易に拡散してしまうことになります。

アプリケーションの各部分の間でコードをコピー・アンド・ペーストしないように注意する必要があります。もし自分がコピー・アンド・ペーストをしていると気付いたら、それを中止し、コピー元のコード・セクションをどう作り直せば再利用できるものになるのかを考え直す必要があります。同様の処理をするコードを 1 つのコードにまとめることによって変更は 1 ヵ所だけですむため、コードの保守は大幅に容易になります。

悪い習慣: 類似したコード・セクションがいくつもある

リスト 9 にはいくつかのメソッドがありますが、これらのメソッドはほとんど同じであり、いくつかの値が所々で異なっているだけです。このようなコピー・アンド・ペーストによって作成されたコードを見つけるのを支援するツールもあります (「参考文献」)。

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

良い習慣: パラメーターを使った再利用可能な関数

リスト 10 はコピーされたコードを 1 つのメソッドに入れるように変更されたコードを示しています。他のメソッドは、この新しいメソッドに作業を任せるように変更されています。コピー・アンド・ペースト用のショートカット・キーを組み合わせて直感的に使うのではなく、共通のメソッドを作成しようとすると、当然立ち止まって考えるようになり、設計に時間がかかります。しかしそうした作業に投入した時間は、共通のコードに変更が必要になった最初の時点で十分回収することができます。

リスト 10. 良い習慣: パラメーターを使った再利用可能な関数
<?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");

?>

まとめ

この記事で説明した良い習慣を PHP コードを作成しながら身に付けると、読みやすくて理解しやすく、保守も容易なコードを作成できるようになります。ここで説明した方法に従って保守が容易なコードを作成すると、コードのデバッグや修正、拡張を行う際のリスクが低くなります。

適切な名前を使用し、コードを小さく分割した構成にすると、コードが読みやすくなります。コードの目的をドキュメント化すると、そのコードの意図を理解しやすくなり、拡張も容易になります。エラーを適切に処理すると、コードが堅牢になります。そして、コピー・アンド・ペーストをやめると、コードを簡潔に保つことができます。

参考文献

学ぶために

  • PHP でオブジェクト指向の設計をするための 7 つの良い習慣を身につける」を読み、手続き型プログラミングからオブジェクト指向プログラミングへの移行を始めてください。
  • Steven C. McConnell 著の『Code Complete』を読み、質の高いコードの書き方を学んでください。
  • Advanced PHP V5 objects」を読み、再利用可能な PHP コードの作成方法を学んでください。
  • 5 つの共通 PHP デザイン・パターン」を読み、PHP にオブジェクト指向の設計パターンを適用する方法を学んでください。
  • Five more PHP design patterns」を読み、さらに多くのオブジェクト指向設計パターンを PHP に適用する方法を学んでください。
  • developerWorks の Architecture ゾーンには、アーキテクチャーの領域でのスキルを磨くための資料が豊富に用意されています。
  • PHP.net は PHP 開発者のための中心的なリソースです。
  • Recommended PHP reading list」を調べてみてください。
  • developerWorks には他にも PHP に関する資料が豊富に用意されています。
  • IBM developerWorks の PHP project resources を利用して PHP のスキルを磨いてください。
  • developerWorks podcasts では、ソフトウェア開発者のための興味深いインタビューやディスカッションを聞くことができます。
  • PHP でデータベースを使うのであれば、Zend Core for IBM を調べてみてください。Zend Core for IBM はシームレスにそのまま使用することができ、インストールも容易な PHP の開発環境かつ本番環境であり、IBM DB2 V9 をサポートしています。
  • developerWorks の Technical events and webcasts で最新情報を入手してください。
  • IBM オープンソース開発者にとって関心のある、世界中で今後開催される会議や業界展示会、ウェブキャスト、その他のイベントについて調べてみてください。
  • developerWorks の Open source ゾーンをご覧ください。オープンソース技術を使った開発や、IBM 製品でオープンソース技術を使用するためのハウ・ツー情報やツール、プロジェクトの更新情報など、豊富な情報が用意されています。
  • IBM とオープンソース技術、そして製品機能を調べ、学ぶために、無料の developerWorks On demand demos をご覧ください。

製品や技術を入手するために

  • 皆さんの次期オープンソース開発プロジェクトを IBM ソフトウェアの試用版を使って革新してください。ダウンロード、あるいは DVD で入手することができます。
  • IBM 製品の評価版をダウンロードし、DB2® や Lotus®、Rational®、Tivoli®、WebSphere® などが提供するアプリケーション開発ツールやミドルウェア製品をお試しください。

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Open source
ArticleID=363851
ArticleTitle=PHP プログラミングのための 5 つの良い習慣を身につける
publish-date=12022008