2012年1月31日火曜日

AmidaMVC:ComponentとAction

AmidaMVCが何をしているのか?

一言で言えば、コンポーネント(部品)を次々と実行するだけ。
格好良くコンポーネントと言ってますが、要するにクラスです。

コンポーネントの登録

たとえば、こんなコードです。


// Controllerを作成、
$ctrl = new \AmidaMVC\Framework\Controller();
// コンポーネントを追加。
$ctrl
    ->addComponent( 'Config', 'config' )
    ->addComponent( 'Router', 'router' )
    ->addComponent( 'Loader', 'loader' )
    ->addComponent( 'Render', 'render' )
;
// フレームワーク実行
$data = new \AmidaMVC\Component\SiteObj();
$ctrl->start( $data );

最初にSiteObjとControllerのオブジェクトを作成してから、
コントローラーにコンポーネントを追加してゆきます。

これらのコンポーネントを順番に実行してゆきます。

クラスなので、実際に走らせるにはメソード名が必要です。
最初は「actionDefault」というメソードを呼び続けます。つまり正常に動いている場合の処理をこのメソード内に書きます。

上の例だと、
・Config:設定用クラス。必要そうな値を設定。
・Router:URLから読み込むファイルを決定する。
・Loader:見つけたファイルを読み込む。
・Render:テンプレートを呼び出してHTMLを出力する。
という処理を順番に行います。

アクション

実行するメソード名は、アクションと読んでいます。
実際はactionAction、最初に「action」をつけて呼び出します。
例えばactionHelloとかです。

もしアクションが存在しない場合。
デフォルトのアクション「Default」を呼び出します。
つまり「actionDefault」のメソードが呼ばれます。

エラー処理の例

途中でエラーが起きたとします。
たとえばRouterでファイルがみつからなかった場合について考えてみます。
  • Routerでファイルがみつからない。
    この場合、Routerはアクションを「_PageNotFound」に変えて、次のコンポーネントに処理を渡します。
  • これ以降、「_PageNotFound」が呼び出されます。無ければデフォルトのアクションを実行します。
  • さて、Loaderの「_PageNotFound」のアクションでは、設定で指定していたファイル(PageNotFound.md)を読み込みます。
    この時点で、表示に必要なデータはそろったことになるので、正常系に戻します。つまり「actionDefault」を呼ぶようにコントローラーに命令します。
  • Renderはファイルが読み込まれているので、正常系の処理と同じになります。
とまぁ、こんな感じで、エラーがあった場合に異常系の処理をして、処理が終われば正常系の処理に戻したりが出来ます。これでフレームワークの設計が簡単になるんじゃないかと思った訳です。

2012年1月30日月曜日

AmidaMVC:今更PHPマイクロフレームワーク作ってみた

ちょこちょこ書いてますが、PHPのmicroframework作ってみました。
今更の感覚が強いですが、
  • 勉強のため、
と思って作ってみました。

でも勉強のためだけで作ることは無かったですね。
実は
  • アミダ式Dispatcher(と勝手に命名)
というロジックを思いついてしまって。
それをMVCフレームワークに応用したら面白そうだなと思ったら、作ってみたくて仕方がなくなり作ったという次第です。

ウェブサイトを作っていて、面倒なのがエラー処理。
ページが見つからないなどの処理をきれいに行いたいと思ってました。

アミダ式の説明は後で行いますが、
標準の処理が簡単なだけでなく、エラーなどの異常系の処理も簡単にできるのではないかと思っています。
まぁ自分が初めて考えついたロジックとは思いませんし、誰かがMVCに応用していてもおかしくはない、というか実はこれがMVCの標準的な処理だった、なんてオチはないといいのですが。こういうのは広い知識を持ってないのがつらいところです。

◆特徴は?

せっかく作ったので、何か特徴があるはず…
  • モデルやビューが無くても動く。
    一つのファイルにPHPとHTMLが混在していても、ちゃんとテンプレート内に入るようになります。もちろんクラスを作っても大丈夫。
  • ルートを設定してもしなくても動く。
  • ファイルビューワーとして、マークダウンファイルやテキストファイルをHTMLとして表示することが出来ます。PHPファイルもソースコードとして表示できたりします。
  • ファイルシステムがベース
    特徴なのかどうか分かりませんがデータベースは必要ありません。遅いと思いがちなファイルですが、今後SSDが普及するにつれ十分なスピードが出るようになるのではないでしょうか?すると簡単にファイルで作れるフレームワークも便利かなぁと。
その他、ファイルを直接修正したりすることも(多分簡単に)出来るはずなのですが、こうなるとフレームワークなのかCMSなのか分からなくなるので、適当なところで切り上げないと。

2012年1月17日火曜日

クロージャーを使ったPSR-0準拠のクラスローダー

PSR-0をベースにしたクラスローダーを探したのですが、全てクラスベースのクラスローダーしか見つかりませんでした。でコピーするのが面倒だったので、クロージャーを使ったクラスローダー作ってみました。
こういうのにクロージャーって便利なんですね。
初めてクロージャーをちゃんと使った気がする。
ソースコードはgitHubのGistにて公開しました。
https://gist.github.com/1620960#file_class_loader_ns.php


特徴は、パラメータ無しで動きます。

◆使い方は、たとえば次のようなクラスをロードする場合。
new AmidaMVC\Folder\SomeClass();

対応するクラスのが次の場所だったとします。
pathto/src/AmidaMVC/Folder/SomeClass.class

こういう場合は、pathto/src/AmidaMVC/bootstrap.php
などに上のGistコードを貼り付けてください。

spl_autoload_register( ClassLoader() );
普通、多分、他のコードを見る感じだとクラスをロードするには、ライブラリで使っているネームスペースとパスを指定する必要があります。
この関数は、呼ばれた場所がライブラリの一番上と仮定して、現在のフォルダーをネームスペース(例の場合はAmidaMVC)、そして現在のフォルダーをのぞいたパス(例の場合はpathto/src/)を設定します。

◆ただし、関数の定義が別ファイルにある場合は、先のbootstrap.phpで

spl_autoload_register( ClassLoader( __DIR__ ) );

とすれば動く「はず」です(動作は未確認)。

◆注意

今コードを見たら、バグがありますね。
少なくとも自分の環境では動いているので、ちょっと修正すれば動くと思います。また時間を見つけたら修正します。

2012年1月11日水曜日

[PHP] Chain of Reponsibility (CoR)を使ったDispatcher

なぜかChain of Reponsibility (CoR)を使ったDispatcherをPHPで書いている。今、必要なこととも思えないが、一度始めたら見切りを付けるまで頭から離れない。仕方ないので書いている感じ。

そもそもは、Html5のローカルアプリ開発にJavaScriptのMVCいるよね、という話から始まって、Mediatorパターンいいよと言われたところからスタートした気がする。

で、JavaScriptの簡易MVC・フレームワークを探したら…
簡単に見つかる。
で、コードを読んでも追いかけられない。
モデルが既に存在しているので、Cenaをそのまま使えない。

じゃあ自分で書いてみるか、となって、
MVCを勉強することにした。


MVCモデルって、要はリクエスト(httpの要求ですね)をもとに、
処理するルーチン(関数でもクラスでも)を決めるだけだよね?
それってなんて言うDispatch?
だからDispatchを書き始めた。

◆車輪の再発明だけど

書いているうちに、簡単なのだと使いづらいと思い始めた。
実際にデータを読み込むところをモデルと考えた場合、
その前後にたくさんの処理が必要になる。

例えば認証、キャッシュ。
認証でエラーがあればモデルなんか読み込む必要がない。
キャッシュにヒットすれば、これまたモデルを読み込む必要がない。
一方、モデルの処理中に致命的エラーが起きたら、まったく別の画面に飛ばす場合もあるでしょう。
で、全部OKだったら、読み込んだデータをHTMLに直す処理を始められる。

つまり途中で処理をかえる必要がある。
思ったより、複雑。

◆CoR

で、CoRを使ってみることにした。
これしか使えそうなパターンを知らなかったからだけど、symfonyやstrutsでも使われてるとどこかで読んだので間違った選択ではなかったみたい。

と、この辺りで気づいたのは、
リクエストから処理するルーチンをDispatchする部分(Router)と、
実際に処理を行うルーチンでのDispatchする部分(なんて言うんだ?)と、
別の話だなと。


2012年1月6日金曜日

2012年の抱負

おめでとうございます。
2012年(平成24年)が明けました。

せっかくなので今年の抱負を書きます。

アウトプットを増やす

もともと書くのは遅いと思うので、今年は余り推敲せずに書くことにして、アウトプットを増やしてみたいです。

もう上の一行で何度も推敲してますがw

Cena-DTAを何とかする

ひとまず日本での特許を取得。
今はアメリカで特許の出願済み、まだ取得は出来てません。

今年はCena-DTAを広める動きをしたいです。

また、コーディングも「着々と」進める予定。

ちゃんと仕事する

今まで適当に仕事をしてきたわけではないのですが。

つい後回しにする悪い癖があるので、今年は頑張りたいです。請求書をちゃんと書く、とかですかね。

それと、受注した仕事が中心だったので、今年は少し能動的に仕事したいです。というかCena-DTAに力を入れてみたいです。

個人的なその他の目標

家族サービスは今までどおり(むしろ増やしたい)
勉強会を月2回ぐらい参加する(家族との協議が必要)
体重を5kgぐらい減らす(減らしすぎないようにするw
東日本大震災を受けて

今年の抱負を考えるにあたり、忘れられないのが東日本大震災。
家族・親戚で直接的な被害をこうむってはいませんが、

「今まで通りでは駄目だ」

という思いをいっそう強くしました。
一昨年のリーマンショック以来感じてたことでもあります。

まだ大きな地震が来るという予想もあります。
いろんなことを見直して、しっかりと生き延びてゆきたいです。

2011年12月14日水曜日

コンポーネント指向について調べてみた

イベント駆動から始まって、次はコンポーネント指向について調べてみました。

いつものようにWikipediaでコンポーネント指向を見ると、まったくわけが分かりません。いや、部品から組み立てようということらしいんですが、それって当たり前だし、ほとんど全てのフレームワークはコンポーネント指向でしょう。

要はGUIのあれと同じ・・・

困って別のサイトを見てたら、いい解説がありました。
全然別のフレームワークの紹介なのですが、上手に説明されていたので、そのまま抜き出します。
コンポーネント指向のフレームワークでは,リクエストごとではなく,コンポーネントが発火するイベントに対するハンドラとして処理を記述します。これは既存のGUIアプリケーションと同様のモデルです。
http://itpro.nikkeibp.co.jp/article/COLUMN/20070305/263875/
既存のGUIアプリと同じモデルだそうです。
あれ、イベント駆動についての最初の例と同じだ。

つまりコンポーネント指向とは、
・ウェブの画面上の各要素に対して、
・サーバー上のクラスを一対一に対応付けて処理する、
という設計方針という意味だと理解しました。

一方、イベント駆動とは、コンポーネント指向を実現するための実装技術なのでしょう。

Yiiのコンポーネントについて想像をめぐらす

YiiのウェブサイトにComponentについての説明があります。コンポーネントとは、パブリックなプロパティを持って、イベントを発生・処理できるとあります。

いまひとつよく分かりませんが、Yii Blog Demoを見ていて、面白いフォーム構造をしているのに気がつきました。

新規ポストの登録で、タイトルの名称は
<input type="text" name="Post[title]" />
となってます。

残念ながらデモのソースコードが見つからなかったので、想像ですが、おそらくPostというコンポーネントクラスが存在するのでしょう。新規投稿をすると、何らかのイベントが発生してPostコンポーネントを呼び出して、titleというプロパティに値を設定して、DBに保存する、という流れになっているのではないでしょうか。

ちなみにコメントの追加では、名前のところは
<input type="text" name="Comment[author]" />
です。

ポスト先を見ると、
http://www.yiiframework.com/demos/blog/index.php/post/1/Welcome%21
Commentという文字がURI内に見当たりません。
どうやってCommentコンポーネントに処理を渡しているのか・・・
単にURIを解析して対応するコンポーネントを決定しているわけではなさそうです。

バインディング

最後に・・・

このように、フォームや画面上に表示された要素と、バックエンド側での処理クラスを関係付けることをデータバインディングと呼ぶようです。

最初にこの言葉を聞いたのがJavaServer Faces(JSF)でした。
調べてみるとWindowsなど様々な場所で使われてる技術・言葉みたいですね。

リクエストを処理→テンプレートで表示、というウェブの作りとはちょっと違っていて面白いですね。

Underscore.phpとarryと_wwの速度比較してみた

PHP Advent jp 2011で書いた_ww(Underscore-Walla-Walla)ですが、せっかくなので他の実装と速度比較してみました。

比較対象は、実装の元ネタの__と、同じくPHP Adventで発表されたarryです。

また比較用のコードとデータはarryで使われていた「悲しき今シーズンの結果」を利用させてもらいました。ありがとうございました。


まずはリファクタリングから

が、利用するにはsortがないし、クラスは二つに分かれてるし。
最初は_wwのリファクタリングから始めました。

まずはgitでブランチを切って、開発開始です。
次にテストクラスを作成してから、さくっとクラスをマージ。
簡単に出来ました。テストがあると、変更するのに気が楽ですね。

速度比較について予測してみる

測定する前に予測を立てます。

まずは、自分の_wwが一番遅いと予想。
理由はマジックメソードを使っているので。

一番早いのはShinさんのarryクラス。
最初からチェーンするようにメソードが組み立てられているので、一番早いはず。

すると中間は、Underscore.php。
これもマジックメソード使ってないけれど、各メソード内での処理があるので、チェーンすると少し処理が増えると予想。

速度比較の結果

ソースコードはgistで公開してあります。
インストールですが、どこかのフォルダーでgit bashを開始して、
git clone git://gist.github.com/1460352.git gist-1460352
git clone git://github.com/shin1x1/arry.git
git clone git://github.com/brianhaveri/Underscore.php.git
git clone git://github.com/asaokamei/_ww.git
と打ち込んで、からgist-1460352内のcompare.phpを走らせてください。
測定ですが、Core2Duo 2.13GHzのWindows Vistaでの結果です。

2.2504210472107  // 素のPHP
5.0997409820557  // arry
9.1629009246826  // Underscore.php
7.959762096405  // _ww

予想通りarryが一番早かったです。
素のPHPに比べて2倍強になりました。結構、速い気がします。

意外だったのがUnderscore.phpより_wwのほうが速かったこと。
何度か走らせると、値が結構変わるので「ほんの少し速い」だけですが、各メソード内での処理が意外と重いのでしょう。

PHPのプロファイリング

そういえばプロファイリング(速度の測定)なんて何年振りです。
PHPだとxdebugを使えば出来るようですが、今回は簡単な関数を自作して計ることにしました。最近使い始めたNetBeansから直接測定結果が見られると便利なんですけどね。