Hack で JSON返すシンプルなマイクロWebアプリケーションフレームワーク書いてみた その(2)

前回とりあえず書いてみたHackで書いたコードですが、

  • strictモードで hh_client check を通したい
  • strictモードで書きたいが Aura.Router が PHP なので Strictモードの指定ができない
  • 高負荷でベンチとると composer がエラーを吐いて hhvm (HipHop VM 3.4.0-dev (rel)) が落ちる

という不満点から改良してみました。

autoload を composer から Aura.Autoload に

loaderは自前で書こうかどうか悩んだんですが、Aura.Autoloadを使うと安定したので、自前で書かずにAura.Autoloadを使うことに。

なので、Hakuを動かすためには composer install が必要ですが、名前空間の定義は app.php で書く形に。

Router を Hack で

とりあえず、マイクロwebアプリフレームワークで最低限必要な、リクエストメソッドと、URIからルーティングできる機能をHackで書きました。preg_matchなどは strictモードでは PREG_SET_ORDER のようなグローバル定数を使うと怒られちゃうので一部 //UNSAFE 指定が必要だったりと、このあたりは妥協。

web/app.php
<?hh // partial

$loader = include(__DIR__ . '/../src/Loader.php');

// add your Namespace to loader like below, if you need.
// $loader->addPrefix('YourVendor', __DIR__ . '/../src');

use Haku\Request;

$app = new Haku\Application();

// simple JSON response
$app->get('/home', () ==> ['message' => 'this page is home']);

// uri parameter
$app->get('/hello/{name}', $name ==> ['message' => $name]);

// with condition
$app->get('/user/{id}', $id ==> ['id' => $id])->addToken(Pair{'id',  '\d+'});

// with query parameter
$app->get('/search', (Request $r) ==> {
        if (!$r->query('q')) {
            http_response_code(400);
        }
        return ['q' => $r->query('q')];
    });

$app->run((new Request()));

ほとんど同じです。loaderが変わったことによる指定の仕方が変わったことと、ルーターをHackで書いたので addToken に渡すパラメータが Pairになったぐらいです。

より速くなったの?

前回までのコードがhhvmをビルドした環境だとセグフォで落ちるようになってしまったため よりstrictモードな構成になったことでどれだけ速くなったかは検証できず。でも、前回同様 PhalconPHP と比べてみると Requests per second で見ると 10% 程度高い値なので、やはり十分速いということは間違いないかなと。

ただし、hhvm構成のほうが php-fpm + phalcon 構成よりメモリ、CPUのリソースを使うように見えました。
これはhhvmをdevでビルドしたからかもしれないので一概に断定はできず。

hh_client 便利

型チェックをしてくれる hh_client は自分で呼ばないといけないので面倒ですが、事前にチェックできるのはやはり便利。
LLなので、チェックでエラーになってても動く場合があといえばあるので CIで必ず忘れずにチェックするとか必要な感じ。

Hack楽しいですね。(辛いけど)

Hack で JSON返すシンプルなマイクロWebアプリケーションフレームワーク書いてみた

久しぶりすぎるブログ更新ですね。。


Hack_(プログラミング言語)

Hackは、Facebookにより開発されたプログラミング言語である。オープンソースとして公開されており、同社が開発したPHP実行環境のHipHop仮想マシン (HHVM) で動作する

前から気にはなっていましたが書いたことはなかった状態でした。

今年のPHPカンファレンスのust (HHVM + Hack == PHP++)を見ていて、Hack欲が高くなり触ってみないとわからないということで JSONを返すだけのいわゆるマイクロフレームワーク(Haku)を書いてみました。

講演のUst はたぶん11/10ぐらいまでだったら録画からみれると思います。

さて、Hackは既存のPHPコードと混ぜて使うことができるので、ルーティング部分はAura.Router を使うことにし、アプリケーション部分とコントローラー部分をHackで書いてみることに。

https://github.com/brtriver/Haku

いわゆるコントローラー部分は今のところこんな感じに。

<?hh // partial
require __DIR__ . '/../vendor/autoload.php';

use Haku\Request;

$app = new Haku\Application();

// simple JSON response
$app->get('/home', () ==> ['message' => 'this page is home']);

// with uri parameter
$app->get('/hello/{name}', $name ==> ['message' => $name]);

// with condition (Aura.Router)
$app->get('/user/{id}', $id ==> ['id' => $id])->addTokens(['id' => '\d+']);

// with query parameter
$app->get('/search', (Request $r) ==> {
        if (!$r->query('q')) {
            http_response_code(400);
        }
        return ['q' => $r->query('q')];
    });

$app->run((new Request()));

Hackは型があって便利というのが一番注目しがちですが、それ以外にもクロージャPHPに比べて明らかにシンプルに書けるのでマイクロフレームワークにはぴったりですね。

array_filterも

 $routeParams = array_filter($route->params, $param ==> !is_object($param));

みたいに書けますし。

あと、メモ化もアノテーションで簡単。
http://docs.hhvm.com/manual/en/hack.attributes.memoize.php

他にも Map, Set, Pair などの多くのコレクションイミュータブルなMap もあります。

PHPだとよくありがちな引数を一つの連想配列で渡すようにしたのは良いけど何が入ってるか毎回メソッド側で確認しなくちゃいけないみたいな問題を解決してくれる Shap も便利。

他にもクラスのプロパティもコンストラクタで渡すのであれば定義を書かなくてもよしなにやってくれる コンストラクタ引数プロモーション とか。

ただし現状リファレンスの整備は完全では無いようで、一部リファレンスに書かれていないメソッドなども存在しているみたい。

あと、あまり参考にならないですが、手元のvm環境ではPhalconPHP(nginx+PHP5.6)で書いたコードとHaku(nginx+hhvm)のHello Worldレベルのベンチマークはほぼ同じで十分速いんだろうなぁという感想。

一番の難点は環境作ることですね。。型チェックしてくれるhh_clientを使うためにがんばってソースから入れてました。。

まだHackらしく書くというのが分かってないのであれですが楽しいですね。

Routerを書き直した続編はこちら