PHP で MVC モデリングの Hello world

近年は MVC というと PHP の Mojavi とか Java の Struts 等の MVC フレームワークが取りざたされます。しかし MVC フレームワークと聞くと何か難しい、MVC も概念は分かるけど使うのは難しい、という人もいるんじゃないでしょうか。
 
というわけで、フレームワークを一切使わず、MVC モデルの Hello, world 的スクリプトを PHP で書いてみました。
 
名前を入力してその人に挨拶する、次のようなコードがあります。これを MVC の構造に変えてみましょう。

nameform.php:
<html>
<head><title>名前入力</title></head>
<body>
   <form action=”” method=”POST”>
       名前:<input type=”text” name=”name”><br>
       <input type=”submit” value=”挨拶”><br>
   </form>
   <?php
      if(!empty($_POST[‘name’])){
          $name = htmlspecialchars($_POST[‘name’]);
          echo “こんにちは、$name!!”;
      }
   ?>
</body>
</html>

これに簡単な MVC モデルを適用すると、次のようになります。

nameform.php:
<?php
    // 挨拶プログラム(Controller)
    
    // 機能部分を読み込み
    require_once ‘include/greeting.inc’;
    // 挨拶を実行し、出力用に特殊文字をエスケープする。
    $result = htmlspecialchars( greet() );
    // 結果を表示。
    require_once ‘template/nameform.html’; // View を呼び出し。
?>

include/greeting.inc:
<?php
  //
  // 挨拶プログラムの Model (ドメイン固有)
  //
  
  require_once dirname(__file__).’/request.inc’; // パラメータ取得用
  /**
   * 名前を取得し、挨拶する。
   * @return string 挨拶の言葉。処理できなかった場合空文字
   * @access public
   */
  function greet(){
      $name = get_parameter(‘name’);
      if($name){
          return greet_to($name);
      } else {
          return;
      }
  }
  
  /**
   * 指定した相手に挨拶する。
   * @param string $name 相手
   * @param string 挨拶の言葉
   * @access private
   */
  function greet_to($name){
      echo “こんにちは、$name!!”;
  }
?>

include/request.inc
<?php
//
// パラメータ操作用ユーティリティファイル (非ドメイン固有 Model)
//
/**
 * 指定した名前を持つリクエストパラメータを取得する。
 * 存在しない場合は空文字を返す。
 * @access public
 * @param string $key 取得したいパラメータの識別名
 * @return string パラメータの中身。存在しない場合空文字
 */
function get_parameter($key){
    return empty($_POST[$key])? : $_POST[‘key’];
}
?>

template/nameform.html:
<!– 名前入力フォーム(view) –>
<html>
<head><title>名前入力</title></head>
<body>
    <form action=”” method=”post”>
        名前:<input type=”text” name=”name”><br>
        <input type=”submit” value=”挨拶”><br>
    </form>
    <!– 処理結果 –>
    $result
    ?>
</body>
</html>

どうでしょう?
PHP のコード(モデル、コントローラ)と HTML デザイン(ビュー)がしっかり分離できているのが確認できると思います。また、メインルーチン(コントローラ)と関数(モデル)が別ファイルに分けられていて、関数はさらに汎用的なもの(共通モデル)と挨拶プログラム固有と思われるもの(ドメイン固有モデル)とに分けています。
 
この程度であればメリットは感じず、ただ書く量が増えるだけに感じると思いますが、これが数百行を超えると大きく変わってきます。
 
– ビューとコントローラを分けることでデザイナとプログラマの作業分担をしやすくなる。
– コントローラとモデルを分けることで同じ処理を行う時にコピーペーストを行う必要がなくなる。
– さらにモデルをドメイン固有モデルと共通モデルとに分ける事で、他のシステムで使い回しても影響がない部品(=共通モデル)が明確になり、再利用性が高まる。
 
感覚が掴めそうな方は、サンプルに挙げた挨拶プログラムを基本として、次のように改善していってみましょう。
 
– ビューに PHP コードでなく Smarty を使うようにする。その場合、htmlspecialchars はやめ、代わりに Smarty の ${result|escape} など escape 修飾子を利用するといいでしょう。
– モデルを関数ではなくクラスにする。
– コントローラに処理を書いていく時は、処理を関数として抽出できないか目を光らせておきましょう。抽出できそうな時はドメイン固有モデルとして抽出、移動しましょう。
– ドメイン固有モデルが増えてきた時は、汎用的な共通モデルにできないか考えましょう。つまり、モデルのコードを一切変更することなく、他のシステムで利用可能かどうか考えましょう。他のシステムでも有用な機能があるのに、他のシステムで使うには変更の必要がありそうなときは、変更せずに済む方法を実装し、共通モデルにすることも検討してみましょう。(内部パラメータの setter を用意する、設定ファイルを読み込めるようにするなど)
 
なお、PHP での MVC モデリングについては Zend コーディング指針の MVC の項も参考になります。
 
参考:
Smarty(日本語マニュアル)