blog

漢のParameterHolder(配列内のnullをどう扱うか)

2010-07-20 05:38:43 PHP Framework Comments: 0
私はSymfony 2が好きとは言えないが、Fabienの向かっている方向性が好きだ。

技術者社長としての精力的な活動。日本人ばりにワーカホリックかつ日本人よりレベルが高いと思う、
密結合による不便さの解消とDIの啓蒙(DI「コンテナ」にまで頭がまわってるかやや心配だが)、
他ライブラリの積極的な取り込み(Zend Frameworkに似通ってきたのは良い帰結だと見なす)、
法人をあげた開発体制づくり(進化を追求するあまりサポートが疎かなのは目をつぶる)、
エンタープライズフレームワークを求める姿勢(ディレクトリが深すぎるのはカスタマイズで何とかする)、
等々、欠点や偏りはあるが己の信念に向かって突き進む様は、ただただ感嘆するばかりだ。

PHPカンファレンス2009で「互換性は無いからな!」と言われたにもかかわらず、
結局カスタマイズバリバリのsymfony 1.4を愛用している身としては、
「あ、DebugPDOが無い」「あ、sfFinderが無い」など、細かいところでsymfony資産が使えない時につらくなる。
いっそのことSymfony 2を使ってsymfony 1.4を作れないものかとすら思う。

PEARのポータビリティとZend FrameworkやSymfony 2の現状ニーズ解決能力に、
Railsの「設定より規約」の思想と、(相反するが)カスタマイズ性の高さが加われば、最強じゃないかなーと思う。
パフォーマンスの最大化とデプロイ機能の強化も「最強」の要件だと思ってるけど、それは最悪自分でやる。
まあともかく将来的にはそうふう時代になって、PHP資産を扱いやすくなるであろう。わくわく。

閑話休題。いまの現実的にはsymfony 1の一部を他フレームワークに持ち込んで使うのは困難であるから、
「持ち込みやすい資産」に慣れておく/作っておくか、資産を持ち込まない方法を考えるしかない。

sfParameterHolderという、やや裏方の軽微なクラスがある。ここにもノウハウが凝縮されている。
このファイル自体に依存性は無いので、使いたいならこのファイルだけを設置すればいい。
もちろん、MITライセンスである事を明記した上で。

・・・という訳にもなかなかいかないから、いちいち手書きで実装する事が多い。
配列操作クラスを実装するには配列の直接の操作方法を理解しなければいけない。

以下にその方法を記す。
すべてPHPマニュアルに書いてあるノウハウではあるが、PHPをきちんと触った人にしかわかりにくい内容だと思う。
// 初期化(clear)
$parameters = array();

// 取得(get)
$value = $parameters[$name];

// nullを存在するとみなした上での存在確認(has)
array_key_exists($name, $parameters);

// nullやを存在しないとみなした上での存在確認
isset($parameters[$name]);

// falseやnullや""や0を存在しないとみなした上での存在確認
!empty($parameters[$name]);

// 既定値を伴う取得
// $value = (hasの内容 ? getの内容 : 既定値);
$value = array_key_exists($name, $parameters) ? $parameters[$name] : '既定値';

// 既定値の代入のみ
if (!array_key_exists($name, $parameters)) { $parameters[$name] = '既定値'; }

// 値のリスト取得
array_keys($parameters);

// 削除(remove)
unset($parameters[$name]);

// 代入(set)
$parameters[$name] = $value;

// 配列の上書き(add) 値がnullでもkeyがあれば上書きされる
array_merge($parameters, $add_parameters);

// 上書きはしないが配列に要素を追加する 値がnullでも上書きしない
$parameters += $add_parameters;

// serialize
serialize($parameters);

// unserialize
$parameters = unserialize($serialized);
PHPの構文に足りていないのは、hasとgetの部分であることがよくわかる。

「既定値を伴うget」は、addで代用できることもある。(sfActionのメンバ変数みたいなのに適用するのは微妙)
あるいはperlみたいに ||= が使えれば良かった。
// perl
$array{$name} ||= '既定値';
まあそれでも、既定値の問題は構文糖の問題に過ぎない。

しかし、hasの問題は言語仕様の根幹に関わる問題だと思う。
「何をもってして値がない状態とみなすか」という解釈が異なっており、3通りの答えが存在するからだ。

「PHPが未定義エラーを出さないこと」が定義だとすればarray_key_existsで良い。
「データベースからレコードを取ってきて、無い物は配列の既定値を適用する」なんて場合は、
issetやemptyを型などに応じて使い分けなければならない。つまり、統一的な解はない。

そういった使い分けの利便性まで考えると、あながち三項演算子作戦もデメリットばかりではないのかも知れない。

「3通りの答え」に対応した、リッチな配列操作クラスを作るのも一つの方法論だろう。
そこにはさまざまな配列機能を拡張するという余地も残されている。

しかし、PHPには配列操作クラスは無く、ただひたすら配列関数が連なっているという文化的背景を考慮すると、
あえてクラス化に頼らずに配列のままで答えを求めるのも、あるいは「漢のParameterHolder」と言えるかも知れない。
includeやクラス操作に関するオーバーヘッドを気にしなくて良くなるのも大きな利点だろう。

PHPに最適なハードウェア構成とは

2010-05-21 02:55:31 PHP Framework Comments: 0
とりあえず適当にハードウェア用意して、開発進めて、納品直前にパフォーマンスが出ない事に気がついて、
お客さんが急に不満を言ってきたり性能要件のハードルを上げようとしてきたりして、
もう納期直前なのにどうするんですかこれ状態になるのを避けるための方策を考えてみた。

まともなロードバランサを導入する

ぶっちゃけ、これに尽きる。
だいたいハードウェア構成を提案しようとしても、既にロードバランサだけは準備されてて、それを使用しろと言われて、
しかもスティッキーセッションに対応しないような軟弱なブツだったりするもんだから、
Webサーバのほうでセッションを記録する先の確保に困って、nfsに置いたらデータは消えるし、
DBに置いたら過負荷でダウンするしで、ひどい目にしか遭わないって事になるわけです。
そんな風になるくらいなら mod_proxy_balancer でも使ったほうが一万倍はマシだろうにね。

メモリを最低4GBは積む

いまどきのフレームワークを使って開発したPHPアプリケーションは、1アクセスあたり32MBくらいメモリ食います。
同時100アクセスさせたかったら3.2GB用意しろってことです。そこまでさばくのは他の要因ゆえ困難だけどね。
言い換えると、8GBあっても使い切れないんじゃないかと思う。CPUやストレージが豪華ならその限りではないけど。

PostgreSQLを使う

mysqlはUNIX Socket(localhost)で使うもの。
DBサーバを立てるなら、使うRDBMSはPostgresであるべきです。
というかmysql使ってもなんもいいことないから、いっそのこと全面的にやめてしまってもいいと思う。
あ、でも、まともなロードバランサがあるんなら、localhostに置いたmysqlを活用するのは賛成です。

APCを導入する

まさか導入しないなんて事はありえないだろうからここに書くまでもないが。

きちんとチューニングする

osとかapacheとかphpとかdbとか、それぞれいじるのよ。方法論はネットに腐るほどあるから割愛。

きちんとプログラミングする

そこで異臭を放っている腐ったスパゲッティを投げ捨ててまともなロジックに書き直すべき。
フレームワークの重さに悪態をつきはじめるのもこのあたりから。
動的に生成しているファイルを静的にしはじめるのもここから。

どのサーバが何台あればいいの?

まず、WebサーバでもDBサーバでもないものは別のハードウェアに載せましょう。
あと、テストサーバと本番サーバは分けましょう。development、staging(testing)、productionに分けるとベター。

その上で、WebサーバとDBサーバがそれぞれ何台にするべきかわからないときは、
とりあえずすべてのサーバに両方ともインストールしてしまいましょう。

DBサーバがすかすかでWebサーバが過負荷だから、
ORMだったものをストアドプロシージャに全部変更する羽目になった、とか、
逆にDBサーバが接続出来なくなりすぎるから、Webサーバにデータベースの複製を置くことにした、
という、やや悲惨な事例もそれなりにあったりします。

結局大規模サイトを作るにはどうしたらいいの?

縦割り行政じゃなくて横割りにするといいと思う。
用途の違ったサーバが別々にあるのではなく、同じ構成のサーバがいくらでも増やせるようにする。
あとは・・・まあ個別にご相談で。

フレームワークの類似性と歴史

2010-04-24 10:21:42 PHP Framework Comments: 0
機会があってAkelosというフレームワークを触ることが出来た。
「CakePHPよりもRuby on Railsに近い」と言われて引き継いだが、おおむね納得している。
この重さはRoR譲りに違いない。

詳細なベンチは結局取らなかったので証拠として出せるものは無いが、
ActiveRecordsでRDBのクエリが不必要に発行されているなら、それは必ず積もり積もってシステムを苦しめる。
countBySql() findBySql() という抜け道を使いつつ、リレーションを神経質に減らせばある程度はマシになる。
それでも手元の環境では、フレームワーク自体の起動コストが1.7秒くらいかかっていてだいぶ重い。

平行して、Smarty2を研究している。
枯れたテンプレートエンジンなので今更「研究」というほどの事では無いのだが、
各種フレームワークが持つ(もしくはsymfon 1.0が持っていた)ヘルパーはSmartyのヘルパーにとても似ている。
今となってはかなり使い勝手が悪いが、次世代のテンプレートフレームワークはSmartyを超える必要がある。
PHPカンファでも「PHPはそれ自体がテンプレートエンジンである」と言う人が居たが、
short_open_tagの廃止をはじめとして、テンプレートエンジンとしては退化している部分も少なくない。
処理速度も大事だが、「まともな文法でテンプレートを書く」という意識がPHPerには希薄なのが悲しいところだ。

フォームフレームワークは、それはそれでどこも似通っているし、
結局のところ「フォームはヘルパーで処理するかフレームワーク化するか二択」になっていると言える。
8年前に愛用していた HTML_QuickForm はあまり使いやすいと言えなかったが、モダンなものもあれに劣るとも勝らない出来だ。

ちなみにAkelosにはSintagsというテンプレートエンジンが搭載されているが、これはSmartyをさらに手抜きしたような文法を持っていて、なじみやすくはある。
templateディレクトリにtplファイルが入っていて、隣にtemplate_cディレクトリがあるあたりで、お察しである。

これらを「改善」するつもりなら、パラダイムシフトを起こさなければいけないのだろうし、
そこまでする気が無いのなら、枯れた技術で妥協するのもアリなのかも知れない。
PHPerの大多数は保守的で新しいもの嫌いな傾向があるし、
そうじゃないPHPerが積極的に新時代の標準を頑張って構築していく必要があるのではないかと思うのだが如何か。

フレームワークのMVC

2010-02-28 22:01:42 薄皮的 PHP Framework Comments: 0
いままでのまとめ。

設計を考えた結果、意外にもMVCの原点に立ち返ってしまった。
今まで自分はMVC否定派だと思っていたがそんな事は無かったぜ。

MVCを正しく成立させるためには、M-V-Cがそれぞれ対等でなければいけないのだ。
symfonyもcakeもMが強すぎる。Vが弱すぎる。
その結果Cが調整弁として多くの役目を果たさねばならず、肥大化する羽目になる。
アクションをシンプルにするのはフレームワークの命題だと言えるので、それではいけない。

対等なMVC。
  • コントローラ
    • ルーティングを行う。ルーティングはアクションに相当する処理を行う。
    • アクションに相当する処理にはすべて必ずルート定義が与えられる。アクション内で分岐が行われて2つの動作を1アクションに記述する事はありえない(禁止)。分岐が起きる場合、一方の処理は別アクションへの変更という形で処理する。
    • ルート定義には従来通りワイルドカードを用いる事が出来る。標準の規約では、URLに該当するビューを(アクションが定義されていなくても)呼び出す事が出来る。ビューのファイル名はルート定義により決定される。
    • よって、アクションはビューの面倒を見る必要性から解放される。Smartyのassignに相当する処理は暗黙に行われる。アクションによって明示的に変更しても良い。
    • アクションに相当する処理は、原則的に設定ファイルに記述する事が出来る。個別のロジックが必要な場合は、そのロジックを指定して呼び出す。(これはstruts.xmlに似ている)
  • ビュー
    • ビューはassignされた変数群とファイルのパスを受け取る。
    • ビューの設定はビュー専用の設定ファイルに記載される。
    • ビューは「受け取ったパスから実際にどのファイルを呼び出すか」を設定する権限を有する。これはアクションのsetTemplate()に相当する。
    • ビューはインクルード機能を有する。これを使い重複する実装をまとめる事が出来る。これはウィジェットの管理にも必須の概念である。
    • ビューはDOCTYPE宣言やヘッダ送出のために、自身の親となるファイルをインクルードする事が出来る。これは設定ファイルに記述する。
    • ビューはウィジェットを有する。たとえばPOSTリクエストを送信する方法はビューが決める。フォームなのかAjaxなのか、どんなインタフェースで送信させるのか、すべてビューが決める。
    • 以上の要件から、Webデザイナーは以下の事項を学習する事で開発に参加する事が出来る。
      • ビューの設定ファイルの記述方法
      • テンプレートエンジンに対応するコーディング方法
      • ウィジェットの定義と利用方法
      • そして、当該プロジェクトにおける個別のルート定義(先行開発の場合はワイルドカード)
  • モデル
    • 機能群とテーブルは一対一で結びつかないという経験から、機能群とは異なる。あくまでテーブルに関する操作しか実装されない。
  • ロジック
    • ロジックはMVCから分離されるが、MVCの要素をそれぞれ内包する。(これはcakeの考え方に近いのかも知れないが、真意はわからない)
    • モデルを操作するための機能群が含まれる。
    • コントローラに追加のコーディングが必要な場合はロジックが呼び出される。
    • ビューのウィジェットを実装するのに必要であればロジックが呼び出される。
  • ライブラリ
    • ロジックはプロジェクトに対して実装されるもので、ライブラリはフレームワークに対して実装されるものであると定義する。
    • ライブラリはロジックの代替になることが出来る。もちろんロジックからライブラリを呼び出すことも出来る。
これでだいたい、作りたいフレームワークの骨格は設計できた。
あとは具体的に実装をはじめていこうと思う。
オープンソースプロジェクトにしたいのだが、作法がわからない。

フレームワークのビュー #2

2010-02-28 15:27:23 薄皮的 PHP Framework Comments: 0
これは書き直しではなく続き。

「フォーム」はビューの管轄である。
(ただし「バリデータ」はモデルの管轄である)
symfony 1.4用語で言うと、errorsとhelpsとwidgetsはビューの管轄ということだ。

ただし、errorsはバリデータを取り扱うためにモデルを必要とする。
当然、保存処理を実行するためにもモデルが必要だ。
コントローラ≠モデルと定義してしまったので、「どのモデルを使うか」を記述しないといけない。

ビューはアクションと同数のビューを持つ。
newアクションとeditアクションで同じビューを使いたければ、そのようにビューが設定する。
ビューにはそれを設定する仕組みを提供する必要がある。

あるテンプレートファイルは別のテンプレートファイルをインクルードする事が出来る。
symfonyのlayout.phpも、親子関係は逆転しているが、インクルードの一環である。
どの親をインクルードするかも、設定ファイルに記述する。

インクルードされるファイルはアクション名と結びつかないため、
「テンプレートファイルがあれば必ず同名のアクションが存在する」とは言えない。
便宜上、たとえばファイル名の先頭に_をつけて区別すると良いかも知れない。

デバッグモードでは、アクションが存在しなくてもルーティングとテンプレートを結びつける事が出来る。
これはモックアップ作成のために必要である。
デザイナー視点だと、これを本番モードでも適用させれると良いのかも知れない。

ルート定義=アクション=ビューとするわけである・・・。

/ と /default と /default/index が同じビューであることを、ビューが定義する必要がある。
/hoge/fuga と /foo/bar が同じだとしても同様である。
ひょっとすると、そっちのほうがいいのかも知れない。
最も設定のボリュームは多くなるが、定義は透明になる。

この場合、バリデート失敗もひとつのアクションとして定義する必要がある。
システムエラー的なものも含めると、より数は増える。
そのかわりアクションはルート定義と完全に同化する。「コントローラ」になる。
なんてこった。一回りして完全なMVC構造になってしまった。

この仕組みにはもう一つメリットがある。
必ずすべてのビューにルートが割り当てられていると、ダミーデータを用いた表示テストが容易に出来るのだ。
もちろん、すべてのパラメタ(たとえば権限管理とか)を適用するのは難しいが。

1 2 3 4 5 次へ 37 件中 1 ~ 5 件目