<?php echo "Hello PHP"; ?>

PHPとJava中心のウェブ技術うんちくブログ

2007年05月

PHPフレームワーク 〜 設定ファイル アクション編2 〜

先日の続き。

設定ファイル (webfront.conf)

[action-mapping]
/new = /src/action/CreateAction
/update = /src/action/UpdateAction
/delete = /src/action/UpdateAction::delete
/welcome = /src/pages/welcome.tpl
/read = /src/action/ReadAction#command

[form-mapping]
/new = /src/form/CreateForm
/update = /src/form/UpdateForm
/delete = /src/form/UpdateForm

[filter-mapping]
/* = CFilter
/update = AFilter, BFilter

[filter]
AFilter = /src/filter/AFilter
BFilter = /src/filter/BFilter
CFilter = /src/filter/CFilter



[action-mapping] の4番目のようにアクションクラスパスではなくファイル名を記述するとフレームワークはそのファイルを直接表示します。HTMLなどのファイルを表示するだけのリクエストのときはこのように記述します。[action-mapping] の5番目はStrutsのLookupDispatchActionと同じような動作が可能で、フォーム画面内にある複数のsubmitボタンごとにそれぞれ処理するメソッドを指定するとこができます。5番目の場合の例でソースを使って説明します。


テンプレートファイル (read.tpl)

<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
</head>
<body>
<form name="read_form" action="/read" method="post">
<input type="submit" value="<?= MessageResources::get('button.list') ?>" name="command" /><br /><br />
<input type="submit" value="<?= MessageResources::get('button.back') ?>" name="command" />
</form>
</body>
</html>



submitのname属性には設定ファイルで#のあとに記述した値と同一の値を設定します。5番目の場合だと /src/action/ReadAction#command なので command です。


アクションクラス (ReadAction.php)

class ReadAction extends DispatchAction
{
    /**
     * ボタンとアクションをマッピングする
     *
     * @return array
     */

    protected function getKeyMethodMap()
    {
        return array(

            "button.list" => "list",
            "button.back" => "back"
        );
    }


    /**
     * 一覧表示ボタンのアクション
     *
     * @param HttpRequest $request
     * @param Form $form
     * @return string
     */

    public function list($request, $form)
    {

        // 一覧表示処理

        return "read.tpl";
    }

    /**
     * 戻るボタンのアクション
     *
     * @param HttpRequest $request
     * @param Form $form
     * @return string
     */

    public function back($request, $form)
    {

        // 戻る処理

        return "read.tpl"
;
    }
}




この動作をさせるアクションクラスはDispatchActionクラスを継承して書き、submitボタンとコールするメソッドをマッピングさせるためにDispatchActionクラスの抽象メソッドgetKeyMethodMap()を実装してメッセージリソースのキーとメソッド名を連想配列でセットしていきます。


メッセージリソース (messages.conf)

button.list = 一覧表示
button.back = 戻る



submitボタンのボタン名を記述したメッセージリソースファイルは上記のようになります。

これでフォーム画面の一覧表示ボタンを押下するとReadActionクラスのlist()がコールされ、戻るボタン押下でReadActionクラスのback()がコールされるようになります。フレームワークの設定ファイルのアクションに関する項目は以上です。次回はフォームについて説明したいと思います。

PHPフレームワーク 〜 設定ファイル アクション編 〜

先日の続きでフレームワーク用の設定ファイルの記述です。

このファイルにはアクションパスに紐付くアクションとフォーム、フィルターのクラスパスを記述します。



[action-mapping]
/new = /src/action/CreateAction
/update = /src/action/UpdateAction
/delete = /src/action/UpdateAction::delete
/welcome = /src/pages/welcome.tpl
/read = /src/action/ReadAction#command

[form-mapping]
/new = /src/form/CreateForm
/update = /src/form/UpdateForm
/delete = /src/form/UpdateForm

[filter-mapping]
/* = CFilter
/update = AFilter, BFilter

[filter]
AFilter = /src/filter/AFilter
BFilter = /src/filter/BFilter
CFilter = /src/filter/CFilter



[action-mapping] にはアクションの設定を書きます。記述の仕方は見ての通りでアクションパス(= の左側でURLで表すと http://hogehoge.com/foo/new の /new の部分)に対するアクションクラスのパスを記述します。具体的な処理の流れで言うと /new でアクセスがあるとCreateActionクラスのexecute()がコールされる流れです。[action-mapping] の3番目のように記述すると /delete に対してUpdateActionクラスのdelete()をコールするようになります。

このフレームワークでは通常抽象ActionのBaseActionクラスを継承したアクションクラスを書きBaseActionクラスのexecute()をオーバーライドして処理を書いていきますが、3番目のようにクラス名のあとにコロン(:)を2回続けてからコールしたいメソッド名を記述することでコールするメソッドを指定するとこが出来ます。動き的にStrutsのMappingDispatchActionと似たような動きが可能になります。

/update と /delete は同じUpdateActionクラスですが /update はexecute()、/delete はdelete()がコールされます。クラスファイルはこんな感じになります。



class UpdateAction extends BaseAction
{
    /**
     * /update のアクション
     *
     * @param HttpRequest $request
     * @param Form $form
     * @return string
     */

    public function execute($request, $form)
    {

        // 更新処理

        return "update.tpl";
    }


    /**
     * /deleteのアクション
     *
     * @param HttpRequest $request
     * @param Form $form
     * @return string
     */

    public function delete($request, $form)
    {

        // 削除処理

        return "delete.tpl";
    }
}




複数の似たようなリクエストを一つのアクションクラスに書けるようになります。

続きはまた明日に。

フレームワークのコンフファイル

大抵フレームワークを使おうとするとXMLで設定情報を書いていきますがXMLの特性と言うのか毎回決まった文言を書くことになるのでいつもまとまりでコピペして一部を変更するお決まりのパターンで書いています。コピペすれば済むことなのでそう大変ではありませんが、それは慣れたフレームワークの話しで新しいフレームワークを使おうとすると、どこに何を設定するのか分らず私のような人にはとても嫌な面倒くさい作業になります。

フレームワークの中には決まったルールに従えばさほど設定を書かなくても良いというお行儀の良いフレームワークもいますが、私はちょっと変なのか書かないのは駄目で複雑なのはイヤでもある程度ピシッと設定は書いて自分で制御しているのを視覚的に確認したい!という願望があるようです。

そんな願望から自分でフレームワークを書くなら設定ファイルは間違いなくXMLではなく簡単に記述ができて視覚的にも一目瞭然なINI形式でいこうと決めていました。複雑な設定を書こうとするとXMLほど知的な書き方はできないのですが「項目 = 値」というシンプルさが気に入ってます。

話しを今書いているフレームワークに戻して、このフレームワークではフレームワーク用の設定ファイルが1つ、アプリケーション用に設定ファイルが1つ、メッセージリソース用に1つと計3ファイルあります。この辺はStrutsと同じです。

フレームワーク用の設定ファイルはアクションパスとクラスのマッピング情報が主で

アクションパス = クラスパス

の一行で書けます。


フレームワークの設定ファイルの例

[action-mapping]
/new = /src/action/CreateAction
/read = /src/action/ReadAction

[form-mapping]
/new = /src/form/CreateForm
/read = /src/form/ReadForm


と記述します。

アクションとフォームがあるところが良くも悪くもStrutsライクですがフォームは必須ではないのでアクションのみでも書けます。例だと /new のリクエストに対してアクションはCreateActionクラスのexecute()が実行されリクエストパラメータの値はCreateFormに入ります。

フレームワーク用の設定ファイルにはアクションとフォームの他にフィルターの設定も記述しますが続きは明日に。

privateとprotectedではまる

class A
{
    private $name = 'ABCDEFG';

    public function getName()
    {
        return $this->name;
    }
}

class B extends A
{
    public function getName()
    {
        return $this->name;
    }
}


よく上のようにベースになる基底クラスを作ってその派生クラスを作るときがある。しかしクラスBのgetName()は期待する値、ABCDEFGは取れない。取れるのは空の値。

このサンプルクラスほどシンプルならすぐ気付くのですが、これが本番だと他の処理が入っていたりしてなかなか気が付かないもので、クラスAのプロパティ$nameがprivateで宣言されているのが原因です。原因が分れば解決策は簡単でアクセス修飾子をprivateからprotectedに替えるか、クラスBのgetName()を

return parent::getName();

に替えてもオッケーです。

基底クラスを書いてから時間をあけて派生クラスを書いたりすると値が取れずたまにはまります。

フレームワークのDispach系Action

今日はPHPのフレームワーク用にStrutsで言うところのLookupDispatchActionとMappingDispatchActionを書いています。元々このフレームワークの基本抽象ActionはMappingDispatchActionを意識した作りになっていて複数のリクエストを一つのアクションにまとめる事もできるようになっています。

StrutsではXMLを使ってこれらの設定を書きますがこのフレームワークでは視覚的にもシンプルで書くのも楽なINIフォーマットを使うことにしています。現時点でアクションに関する設定の記述は


/sample = /src/action/SampleAction
/read = /src/action/TestAction::read
/list = /src/action/TestAction::list
/sample2 = /src/action/Sample2Action#method


のように書けます。

一番上は基本の書き方で/sampleのリクエストに対してSampleActionクラスのexecute()をコールする書き方です。

二番目、三番目は/readリクエストに対してTestActionクラスのread()、/listリクエストに対してはTestActionクラスのlist()をコールする書き方です(MappingDispatchAction風)。

四番目は/sample2リクエストに対してSample2Actionクラスのsubmitボタンにマッピングされたメソッドをコールする書き方で#に続くmethodはテンプレートのsubmitタグのname属性の値が入ります。これでどのsubmitボタンからのリクエストか判断します(LookupDispatchAction風)。

明日はもう少し詳しく設定ファイルについて書こうと思います。

PHPのフレームワーク

仕事でJavaを使うと間違いなくフレームワークを使います。最近は何だかずっとStrutsを使っている気がしていますが、PHPだとフレームワーク使用のプロジェクトがほとんど無かったような気がしてます。

そんなPHPでも実はいくつもフレームワークがあるようで、私がよく聞くのがEthnaとSymfony。少し前だとMojaviなどもありましたが、最近だとRails似のCakePHPも耳にするようになってきました。

私の中ではPHPって気軽にアプリ・サイトを構築できるお気楽なイメージがあって、ごちゃごちゃXMLで設定が必要なお堅いフレームワークなんて必要なのかなと正直思っていますが、Javaに慣れきってしまうとベタ書きのPHPのソースを解析するのもちょっと気が引けてきます。

そんなこんなで仕事で良く使っているStrutsのアクションフレームワークの仕組みを持ちつつXMLで延々と設定ファイルを書くこともなく(そもそもXML自体は情報を整理しやすくてその意味でいいフォーマットなのですが無駄に長くなるところがキライ)、たいした設定をしなくてもDIコンテナとか依存性を注入できちゃって、しかもPHPの『気楽にコーディング』を損なわない程度にソースに縛りを付ける軽量フレームワークがあったらいいな、というところから初まって現在そんなフレームワークを作っています。

現在の進捗は80%ほど。
例えばテンプレートの内容を表示するだけの例

リクエストしたURL
http://hoge.com/foo/sample


アクションクラス

class SampleAct extends BaseAction
{
    /**
      * サンプルアクションです。
      *
      * @param HttpRequest $request
      * @param Form $form
      * @return string
      */
    public function hello($request, $form)
    {
        $str = "Hello PHP!";
        $request->set("Hello", $str);

        return "Hello.tpl";
    }
}


テンプレート

<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
</head>
<body>
<?= $request->get("Hello") ?>
</body>
</html>


コンフファイル

 ・
 ・
/sample = /src/action/SampleAct::hello
 ・
 ・


のように書けます。
設定は上記の一行です。
上の例だとコールするメソッド名も指定しています。

詳細はこのブログに少しずつ書いていくので興味ある方お付き合いよろしくお願いします。

PHPのインクリメント速度

プログラム中でよく使う1を足したり引いたりする場面で、例えば1を足すなら

$count = $count + 1;

と書いたり

$count++;

と書いたり

++$count;

と書いたりできますが、どれが一番速いのか。
検証してみました。

まずは
$count = $count + 1; を100万回計算するものを20セット行った平均が 0.32688 秒。
次に $count++; だと 0.27664 秒。
最後に ++$count; だと 0.258985 秒。

1を足すなら前置インクリメントが一番速いようです。

is_objectの挙動

PHPには変数の中にオブジェクトが入っているか確認する is_object() という関数があります。

PHP マニュアルより抜粋

>説明
>bool is_object ( mixed $var )
>
>与えられた変数がオブジェクトかどうかを調べます。

この時のオブジェクトって一体なんなのかはっきり把握していなかったのでこんなスクリプトを書いて検証してみた。


class Object
{
}

$str = "12345678";
echo "string -> ";
echo is_object($str) ? "true" : "false";

$int = 123456;
echo "int -> ";
echo is_object($int) ? "true" : "false";

$arr = array(1,2,3,4,5);
echo "array -> ";
echo is_object($arr) ? "true" : "false";

$arr2 = array("A" => "AAA", "B" => "BBB");
echo "hash -> ";
echo is_object($arr2) ? "true" : "false";

$bool = true;
echo "boolean -> ";
echo is_object($bool) ? "true" : "false";

$nl = null;
echo "null -> ";
echo is_object($nl) ? "true" : "false";

$obj = new Object();
echo "Object -> ";
echo is_object($obj) ? "true" : "false";

$obj2 = (object)$arr;
echo "Object2 -> ";
echo is_object($obj2) ? "true" : "false";

$obj3 = (object)$int;
echo "Object3 -> ";
echo is_object($obj3) ? "true" : "false";


結果は


string -> false
int -> false
array -> false
hash -> false
boolean -> false
null -> false
Object -> true
Object2 -> true
Object3 -> true


なるほど。
なかなか使えそう。

まずはご挨拶

みなさま、初めまして。

お仕事の方でJavaとPHPでガリガリコーディングしたり設計したりしている takahirown です。

お仕事で知ったコトや日々の中で発見した興味あるコトをだらだらと綴っていこうと思っていますので、気長に細くく長お付き合いのほどよろしゅう。
最新記事
Archives