標高+1m

Don't be rational.

サーバーサイドMVC

まずクラスは使わない。なぜなら必要ないから。せっかくモジュラーな関数をわざわざそうじゃなくする意味がない。クラスはレアケースを除いて基本的には悪。

モデルはRead系のAPIとWrite系のAPI名前空間を分ける。

<?php
/* Articles.php */

namespace Articles\Write;
function mkArticle ($title, $text, $tags) {
  /*バリデーションとかして連想配列を作って返す*/
}
function addArticle ($article) {/*DBに保存*/}

namespace Articles\Read;
function getArticles ($filter=null) {/*DBから読み出し*/}
function getArticle ($id) {}

ビューはモデルのRead系APIを直接見る。コントローラがモデルを読んでビューに値を渡す従来のやりかたは頭おかしい。

ここでrenderArticleは面倒だからインラインでhtml書いてるけど実際はテンプレートの呼び出しとかになる。

<?php
/* ArticlesView.php */

namespace ArticlesView;
use Articles\Read as Articles;

function renderArticles () {
    $articles = Articles\getArticles();
    array_map('renderArticle', $articles);
}

function renderArticle ($article) {
    ?>
      <div class="article">
        <h2><?= $a["title"] ?></h2>
        <p><?= $a["text"] ?></p>
      </div>
    <?
}

function renderArticleOfId ($id) {
    renderArticle(Articles\getArticle($id));
}

コントローラはラウティングライブラリを使って書く。モデルのWrite系APIとビューのAPIにアクセスできる。

<?php
/* index.php */

namespace App;
use Articles\Write as Articles;
use ArticleView;
use Routy\Router;

$app = new Router();

$app->post("articles", function () {
    Articles\addArticle(Articles\mkArticle($_POST["title"], $_POST["text"], $_POST["tags"]));
    redirect("/articles");
});

$app->get("articles", function () {
    ArticleView\renderArticles();
});

$app->get("articles/{alnum}", function ($id) {
    ArticleView\renderArticleOfId($id);
});

$app->run();