PHPのマイクロフレームワーク「Slim」を使ってみたら本当にスリムだった話
こんにちは。プログラマー小野です。
個人の好みは別として、私が普段の業務で取り扱うプログラミング言語はPHPの占める割合が圧倒的です。
WEBの案件がメインですし、対応しているサーバーが多い(むしろ今日び対応してないサーバーは在るんだろうか?)ですもんね。
WEBサイト製作ならWordPressのようなCMSを利用しますし、ある程度の規模のシステムを組むのであれば何らかのフレームワークを採用しますので、生のPHPを書く機会はすっかり無くなりました。
とは言えLaravelやCakePHPのような有名ドコロは、多機能であるが故にフレームワーク自体が超巨大なんですね。
(WordPressを手動でセットアップした事がある方なら覚えがあるかもしれませんが、インストール直後のWordPressであっても数百〜数千のファイル群によって構成されています)
Pythonなんかだと「マイクロフレームワーク」ってよく聞くフレーズなので、PHPでももっと手軽にセットアップできて小さい構成のフレームワークはないもんか?と思い探してみると、、、
PHPのためのマイクロフレームワーク Slim
ありました、ありました。そのものズバリが。
Slim a micro framework for PHP
さっそくインストールしてみましょう。
(※ 環境はMac、composerはインストールされている前提です)
公式サイトのチュートリアルに従ってターミナルで以下のコマンドを実行します。
$ php composer.phar create-project slim/slim-skeleton [my-app-name]
「my-app-name」の部分は任意の名称に置き換えてくださいね。
これで以下のようにファイル群が構成されます。
この時点でローカルサーバーを起動すればサンプルアプリケーションは動作します。
引き続きチュートリアルに倣って以下ですね。
$ cd [my-app-name] $ php -S localhost:8080 -t public public/index.php
ひとまず動作確認は取れました。ここまで5分足らずです。
(何やら「タイムゾーンをちゃんと設定しろよ」とWarningが出てますが、ここでは無視します)
最小構成までファイルを減らしてみる
ただ、このままだとまだ「マイクロ」感が弱いですよね。
どこまでマイクロにしても動くのか、最小構成までファイルを減らしてみたところ、
ここまで削れました。
具体的にはインストール直後の状態から public/index.php を一階層上(my-app-name)に移動した上で、index.php と vendor ディレクトリ以外を全削除します。
index.php は以下のように実装します。
(公式サイトのトップに書いてあるコードですね)
get('/hello/{name}', function ($request, $response) { $name = $request->getAttribute('name'); $response->getBody()->write("Hello, $name"); return $response; }); $app->run();
再度ローカルサーバーを立ち上げて
$ php -S localhost:8080
ブラウザから http://localhost:8080/hello/world にアクセス、ハローワールドが表示されることが確認できました。
テンプレートを使ってhtmlを表示させてみる
このままではWEBページとしてアレなので、キチンとしたhtmlも出力してみます。
$app->get('/hello/{name}', function ($request, $response) { $args = $request->getAttributes(); $renderer = new Slim\Views\PhpRenderer(__DIR__ . '/templates/'); return $renderer->render($response, 'index.phtml', $args); });
Slimはテンプレートエンジンも組み込まれていますので、別個で用意したテンプレートファイル(ここでは index.phtml)にデータを渡して動的なページを生成することができます。
sqliteを置いてDBアクセスしてみる
せっかくフレームワークがマイクロなのでDBも軽めのを選びたいということで、sqliteにしてみましょう。
プロジェクトのディレクトリ直下に「db」ディレクトリを作成し、db.sqlite3 を用意します。
DBには「users」テーブルがあり、レコード全件を取得するとします。
$app->get('/hello/{name}', function ($request, $response) { $db = new PDO('sqlite:db/db.sqlite3'); $sql = 'SELECT users.id, users.name, users.email FROM users'; $query = $db->prepare($sql); $query->execute(); return var_dump($query->fetchAll(PDO::FETCH_ASSOC)); });
いっさい整形していませんがDBにアクセスでき、データが取得されることは確認できます。
sqlite、大規模なシステムに使うには少し心配ですがMySQLのようにDBサーバーを立てるには大袈裟すぎる程度のプロジェクトであればデータベースとしては過不足ないですね。
jsonを出力してみる
上記は取得したuserテーブルのレコード全件をダンプしただけですが、$response->withJson()に渡せばjson形式に変換することができます。
$app->get('/hello/{name}', function ($request, $response) { $db = new PDO('sqlite:db/db.sqlite3'); $sql = 'SELECT users.id, users.name, users.email FROM users'; $query = $db->prepare($sql); $query->execute(); return $response->withJson($query->fetchAll(PDO::FETCH_ASSOC)); });
(※ 最後の行だけが上と異なります)
Content-Type が「application/json」になっていますし、マルチバイト文字もエンコードされてますね。
Slimのルーティングでは通常のGET、POSTに加えてPUT/PATCH(更新)とDELETE(削除)のHTTP Requestにも対応しているので、例えば
$app->get('/users/{id}', function ($request, $response) {...} $app->post('/users', function ($request, $response) {...} $app->put('/users/{id}', function ($request, $response) {...} $app->delete('/users/{id}', function ($request, $response) {...}
以上のようにルーティングを組んで、それぞれにSELECT、INSERT、UPDATE、DELETEのSQLを書けば簡易的なREST(風)APIアプリケーションとして動作できそうですよね。
あー、何となく使い道が見えてきました。
フロントエンドをReact.jsなどのJavaScriptで実装すればテンプレート1枚とindex.php + dbだけの構成でも何とかなりそうかな?
夢は膨らみます。
最後に
とかくデジタルなものは実体がない分、大きさ(ファイル数やデータサイズ)を意識することが希薄で、勢い「アレもコレも」と盛り込み過ぎて気が付いたら身じろぎもできないくらい肥大化、という失敗例はプログラムに関してだけではなく「サービス」と大きく括っても当てはまることのように思います。
小さくて簡素であることは決してネガティブな要素ではなく、「Keep it simple, stupid(シンプルにしておけ阿呆!)」の教え通り忘れてはならない戒めですね。
そういえば「大は小を兼ねる」って、最近聞かなくなったような気がします、、、