PHPでOOP
PHPを使ってプログラミングするとき、 プロシージャ指向(手続き型、構造化プログラミング)でもできますが、 オブジェクト指向を使った場合の恩恵を享受するために、 PHPでオブジェクト指向プログラミングの勉強をしてみましょう。 <目的> PHP5でオブジェクト指向プログラミングを行なうための知識を習得する。 (PHP4のOOPもOK、このスレが1000に行く前にPHP6が出たらPHP6のOOPもOK) <方向性> ・このスレは、プログラミング初心者、PHP初心者の勉強の場として利用することを前提にします。 ・PHPのOOPの話題に限定します。 (Ruby、Python、Javaなど他言語のOOPについては、その言語のスレッドでお願いします。) ・PHPのOOP学習に役立つ本、WEBサイトの紹介をお願いします。 <その他> ・略記は、「OO」=「オブジェクト指向」、「OOP」=「オブジェクト指向プログラミング」でお願いします。 ・質問をする人はなるべくトリップを付けましょう。 ・荒らし、煽り、叩き、気違いは無視・無干渉でお願いします。 このスレで、今日から貴方もOOP!!!\(^o^)/ ちいたんのソース見てみたけれど、 class CObject ってあって、必ずそれが継承されて作られてるよね。 これの都合って何なんだろう。(メリットは何?) javaも.NETもこういう基本クラスがあるよね。 >>208 サンクス。 でも、オーバーロードが出来ない場合は逆に足かせになる可能性もあるね。 例えば、継承されているクラスが沢山ある状況でObjectクラスに メソッドを追加する場合とか。 喋るのはコントローラとモデル コントローラとビュー 基本的にはね 少ない数のクラスを書いたり読んだりする程度であれば、すぐに分かるのだが、 フレームワークレベルのクラス構造となると、その構成が全く分からなくなって 来るんだよなぁ。何かコツのようなものはあるのかな? 処理の内容を追いかけると、次々に別のクラスに処理を渡す構造になっていて、 最後はあっけない、みたいな感じだ。 フレームワークを作る場合のクラスの設計手法を身につけるなどしないと いけないのかも。 メンバに定義はしていないけれど、メソッドではその変数をエラーが 出ないように処理が書かれているっていう書き方は多いようだ。 そうしておけば、そのフレームワークを使う人は、クラスを継承して メンバに値を代入するだけで良い。 このサイト、説明は分かるのだが、具体的に作っているコードは MVCのうちどれにあたるのかがいまいちです。 ttp://www.stackasterisk.jp/tech/php/phpMvc01_01.jsp Result.php は、Viewにあたるものという解釈でいいんですよね? PHPでMVC関連のサイトを紹介で貼っておきます。 特集:第3回 PHPを思うままに操れるようになる「MVC」と「Smarty」 (1/4) ttp://www.itmedia.co.jp/enterprise/0402/19/epn01.html PHPでね、イベントドリブンなWEBフレームワークとか自作してみるといいかも。 例えば、サブミットボタンの処理ハンドラがオーバーライドで記述可能で そこでフォーム値をモデルに渡して処理させるみたいなやつ・・ 「POST」や「GET」とかローレベルの概念は全て隠蔽されてて フレームワークにイベント発生時のロジックだけ記述して終わりみたいなの・・・ そしてPHPであれこれ試行錯誤したあと、ASP.NETとか参考にするとね PHPでOOPするバカらしさに気付くかもしれない・・・OTL ASP.NET は、ちょっとだけやってみたことあるけど、概念的に違和感が あって、やらなくなったな。 ある程度Webアプリを学んだ事のある人には便利なんだろうけれど、 初めて学ぶ人には、ドキュメントが少なすぎだし、いきなりイベントドリブンで やるのはどうかと思った。 で、まずは、Webアプリの基礎をやるという意味合いでPerlをやってみた。 で、今はPHPをやっている。PHPそのものがOOPに完全な対応をしていない ので、これで大規模なアプリを組むことも無いかなと思っている。 対応したとしても、それからノウハウが出てくるので、さらに数年先になる。 でも、学ぶ時は、既存のモジュールを使って早くやるのよりも、モジュール なしの状態で、モジュールを作ってみる方がいいので、とりあえず今は PHPでOOPです。 >>217 多分、その違和感のある概念がOOPの本質だと思うよ。 そしてその概念は、洗礼された実装に触れることでしか 身につかないとも思うんだ。 初心者こそイベントドリブンを真っ先に学習したほうがいいよ。 最終的に、理解し易く安全な実装方法に結びつくと思うからね。 PHPでOOPで実装ってケースはありだとは思うけど、 概念は別で学習した方が効率的だと思うんだ。 OOPに取り付かれているとか良くわからんw 普通にプログラミングしていると使うだろ? switchに取り付かれているとかそういうレベルに聞こえるんだが。 MVCモデルでプログラミングする場合、Model から View へ処理を渡す経緯は、 どっちが正しいのかな? ・Control クラスのメソッド内で、Model クラスと View クラスのインスタンスを生成する。 Control クラスが、Model からデータを受け取り、View クラスへデータを渡し、 描画指示を出す。 ・Model クラスのメソッド内で、View クラスのインスタンスを生成する。 Model クラスが、Viewクラスへデータを渡し、描画指示を出す。 Control クラスは、View クラスを一切操作しない。 それとも、こういうところまでは理論的には定めていないので、 ケースバイケースであり、どちらがよいというものは無いということかな? PHPでイベントドリブンですか?(・∀・) …こんなのありました。^^ PHP イベントドリブン に一致する日本語のページ 約 10,600 件 ●PRADO http://www.pradoframework.com/wiki/index.php/Ja:What_is_PRADO >PRADO はコンポーネントベースかつイベントドリブンなウェブアプリケーションを開発するためのPHP5フレームワークです。 ●S2Prado.PHP5 http://labs.s2php5.jp/s2prado.php5 http://blog.xole.net/article.php?id=553 >S2Baseの方は待望のPRADO対応。 ●Piece Framework http://trac.piece-framework.com/piece-unity/wiki/ja/Start >Piece_Unityは、Visual BasicやDelphiのようなイベントドリブンなフレームワークです。 ●Delphi for PHP http://www.codegear.com/jp/products/delphi/php http://orz.qzlab.com/yamagw/index.php?Delphi%20for%20PHP%A4%CE%BB%C8%A4%A4%CA%FD >イベントドリブンなロジックの実装が容易に実現する。 ●Pharon http://pharon.lolipop.jp/ >最大の特徴は、wizard によりイベントドリブン型のスケルトンを自動作成することです。 インターネット越しにイベント処理をさせるのが、WEBプログラミングの特徴ですね。 イベントドリブンは、PHPよりもむしろFlash/Flexとかで使われる仕組みなのでしょうか? レガシーの中心でのOOP http://kaede.to/ ~canada/doc/2005/07/06/ >Webプログラミングにおいて、ブラウザとのやり取りがレガシー(古典的)なデータ交換に過ぎず、これがWebプログラミングを難しくしている >Webは1ページごとに毎回セッションが起動し、ドキュメントを表示するとすぐ終了する。 >オブジェクト指向プログラミングにおける利点の1つであるイベントドリブンなプログラミングは不可能だ。 >何しろ1セッションに1イベントしか発生しないのだから。 >と同時にセッション状態を保存する必要も出てくる。 http://www.adobe.com/jp/devnet/flex/articles/framework_beta_print.html >インタラクティブ性に優れたイベントドリブンなインタフェイス http://www.atmarkit.co.jp/fwcr/rensai/flex203/01.html >イベント処理によってアプリケーションを構築する手法はイベント駆動型(イベントドリブン)と呼ばれます。 http://www.azul.systems-noel.jp/item_9.html >Flex2はイベントドリブンなので、ビューに起こったイベントをコントローラのリスナでキャッチするように意識すれば、MVCの分離はきれいにできるようになっています。 >なんかほんとにJavaのSwingを使ってるような気分になりますね。 http://bitmap.dyndns.org/blog/archives/001215.html >イベントドリブンモデルには、主に以下の 4 つのオブジェクトが登場する。 >>220 >・Control クラスのメソッド内で、Model クラスと View クラスのインスタンスを生成する。 こっちの方が、Controlにまとまっている分だけスッキリしており、分かりやすいコードになるんじゃないでしょうか? >>224 レスありがとうございます。 1番目の方にすると、Modelクラスから取得したデータを Viewクラスに渡すことになるので、その分余計にメモリや CPUを消費してしまうのでは、と心配になって聞いてみましたが、 考えてみると、コードの見易さなどを優先するのがOOPですので、 そちらの方がいいですね。 でも、フレームワークのソースなどを見ていると、 各クラスが、メンバに、別のクラスへのリファレンスを持ってたり するので、もっと理論に従った組み方があるのかも、と思っています。 >>184 ファイル:全部で8つ。index.phpを実行する。 抽象クラスと具象クラスに実装を分けてみました。 csv.txt(※前回と同じ) index.php cfcontrol.php アブストラクトとして実装 cfview.php cfmodel.php コンクリートとして実装 data_model.php index_view.php output_view.php [config.php] <?php // 実際の処理を行うスクリプトをインクルード include("./index_view.php"); include("./output_view.php"); include("./data_model.php"); // 最初に呼ばれるビューのプレフィックス設定 define ('INDEX_VIEW_PREFIX', "Index"); // モデルクラスのプレフィックス設定 define ('MODEL_PREFIX', "Data"); ?> [index.php] <?php include("./cfcontrol.php"); $view_key = $_POST["view_key"]; $data = $_POST["data"]; $app = new CFControl($view_key, $data); $app->Execute(); ?> [cfmodel.php] <?php class CFModel { var $file_name; // 読み込むファイル名 function CFModel() {}// コンストラクタ function Execute($param) // パブリックメソッド { return $this->_OnExecute($param); } function _OnExecute($param) // 仮想メソッド { trigger_error('オーバーライドしてね。', E_USER_ERROR); } } ?> [cfview.php] <?php class CFView { var $file_name; // POSTするファイル名 function CFView() {} // コンストラクタ function Execute($param) // パブリックメソッド { return $this->_OnExecute($param); } function _OnExecute($param) // 仮想メソッド { trigger_error('オーバーライドしてね。', E_USER_ERROR); } } ?> [cfcontrol.php] <?php include("./cfview.php"); include("./cfmodel.php"); include("./config.php"); class CFControl { var $_view_key; // 呼び出すビューのプレフィックス var $_data; // モデルに渡すデータ function CFControl($view_key, $data) // コンストラクタ { $this->_view_key = $view_key; $this->_data = $data; } function Execute() // パブリックメソッド { // モデルオブジェクト動的生成 $model_class_name = MODEL_PREFIX . 'Model'; $model = new $model_class_name(); $param = $model->Execute($this->_data); // ビューオブジェクト動的生成 $view_key = $this->_view_key; if ($view_key == "") $view_key = INDEX_VIEW_PREFIX; $view_class_name = $view_key . 'View'; $form = new $view_class_name(); $form->Execute($param); } } ?> [data_model.php] <?php class DataModel extends CFModel { function DataModel() // コンストラクタで取得先のファイル設定 { $this->file_name = 'csv.txt'; } function _OnExecute($param) // オーバーライドメソッド { $INFILE = fopen($this->file_name,"r"); $data = fgets($INFILE, 1024); fclose($INFILE); $data = $data . ", " . $param; return $data; } } ?> [index_view.php] <?php class IndexView extends CFView { function IndexView() // コンストラクタでPOST先のファイル設定 { $this->file_name = 'index.php'; } function _OnExecute($param) // オーバーライドメソッド { echo "<html><body>"; echo '<form method="POST" action="' . $this->file_name . '">'; echo '<input type="hidden" name="view_key" value="Output">'; echo '<input type="text" name="data"><input type="submit" value="送信">'; echo "</form></body></html>"; } } ?> [output_view.php] <?php class OutputView extends CFView { function OutputView() // コンストラクタでPOST先のファイル設定 { $this->file_name = 'index.php'; } function _OnExecute($param) // オーバーライドメソッド { echo "<html><body>"; echo '<form method="POST" action="' . $this->file_name . '">'; echo '<input type="hidden" name="form" value="Index">'; echo "$param<br>"; echo '<input type="submit" value="戻る"></form></body></html>'; } } ?> >>226-232 サンプルソースありがとうございます。 抽象クラスの書き方に慣れてますね。私はこのあたりを しっかりとやってなかったのでちょっと苦手です。 ま、しっかりと勉強していきたいと思います。(^^; ソースを読んでいて、1点気になったので質問をしたいのですが、 class CFView と class CFModel において、以下のように パブリックメソッドと仮想メソッドを作り、パブリックメソッドから 仮想メソッドを実行する形式にソースを書いた理由は何でしょうか? 出来ましたら、この設計にした意図を教えていただきたいと思います。 function Execute($param) // パブリックメソッド { return $this->_OnExecute($param); } function _OnExecute($param) // 仮想メソッド { trigger_error('オーバーライドしてね。', E_USER_ERROR); } >>218 レスありがとうございます。 イベントドリブンそのものは、VBでWindowsアプリを組んでやったことがあるので すぐに入れたのですが、Webアプリを作る際、イベントドリブンでしかやった事が 無いというのは致命的だと思ったので、PerlやPHPでやってみています。 (ASP.NETは、便利ではあるが、IISを使えとか、.NET Frameworkを使えとか 非常に限定される。) 構造化プログラミングで、あまり命名規則を考えずにプログラムをしていると、 グローバル変数や関数が多くなった時、その把握が出来なくなったりする わけなのですが、そういう苦労する体験をした後、OOPを習うと、その便利な部分が 見えてくるわけです。OOPは経験による結論的な理論だな、と理解できるわけです。 その理解のために、とりあえず、苦労をする方法(PHP で 0 から OOP)で やってみているのです。 今は、このように考えています。 >>233 PHP4では全てパブリックだけど例えばC#では以下の実装になるんだ public object Execute(object parpam) protected virtual object _OnExecute(object parpam) CFControlから_OnExecuteメソッドを隠蔽する意図なんだよ。 _OnExecuteはCFViewやCFModelのサブクラスにだけ見えれば十分なんだ。 >>235 暖かいですねぇ。 >>236 なるほど。ありがとう。 ソースを読んでいて気になった点がありますので、質問させていただきます。 includeの構成についてです。まず、各ファイルに書かれているincludeの部分をまとめます。 [index.php] include("./cfcontrol.php"); [cfcontrol.php] include("./cfview.php"); include("./cfmodel.php"); include("./config.php"); [config.php] // 実際の処理を行うスクリプトをインクルード include("./index_view.php"); include("./output_view.php"); include("./data_model.php"); これは、MVCフレームワークは、以下の3つのファイルであり、 [cfcontrol.php][cfmodel.php][cfview.php] それを拡張する形で、残りの6つのファイルを付け加えた形 なので、このようなincludeの構成ということでよろしいのでしょうか。 includeをばらばらとさせるよりも、以下のように整理したほうが となんとなく思ったりもしたのです。 [index.php] include("./config.php"); [config.php] include("./cfcontrol.php"); include("./cfview.php"); include("./cfmodel.php"); include("./index_view.php"); include("./output_view.php"); include("./data_model.php"); MVC?な俺にはここが一番わかりやすかった 実例コードが載ってるのがいい PHPでMVC第1回:前編 ttp://www.stackasterisk.jp/tech/php/phpMvc01_01.jsp ソースコードをちょっとだけ改変したものを作ってみた。 メモとかを残していく都合もあると思ったから、HP解説してみた。 ttp://www.geocities.jp/narutobakijp2/ 本当は、>>1 さんがソースの管理とかもしてくれたりしたら、うれしいw >>243 CFViewクラスに具体的な実装をしちゃダメなんだよ。 そもそもHTMLのフォーム処理とかは、あとでPEARとか使えばいい。 サブクラスをうまく呼び出す仕組みだけを実装していくんだ。 >>244 > サブクラスをうまく呼び出す仕組みだけを実装していくんだ。 kwsk >>246 構造化プログラミングはルーチンを呼ぶ方向で実装すると思うけど OOPではルーチンに呼ばれる方向で実装して行く感じだよ。 大枠の骨組みだけを抽象クラスで作成して、処理は具象クラスで行うんだ。 インターフェイスさえ同じならあとで個別にパーツを交換出来たりするからね。 だったら基底クラスのメソッドなんて数個で十分じゃないかと思うんだ。 やたら複雑でよくばりな機能のクラスなんて、再利用の価値がないからね。 >>247 レスありがとうございます。 > 構造化プログラミングはルーチンを呼ぶ方向で実装すると思うけど > OOPではルーチンに呼ばれる方向で実装して行く感じだよ。 私は、継承を活かした設計をした事が無かったので、ちょっと方向性を 誤ってしまったようですね。 Viewは、表示をつかさどるのだから、html表示を請け負うのでは、と 思っていたのですが、それよりも抽象的な枠組みを定義するという ことですね。 となると、html表示は(PEARを使わないのであれば、)htmlタグの 記述を行うCF_HTMLクラスを作り、Viewの具象クラス内で インスタンスを生成ということですよね? >>248 HTML処理のヘルパクラス作成はあまりOOPの勉強にならないとも思うんだ。 もう既に頭の中で実装出来ているだろうし、引数を関数で処理するだけでしょ? それよりも例えばPEARのHTML_QuickFormやテンプレートレンダラのSmartyを Viewと連携させる仕組みとかを考えたりした方がよっぽど面白いよ。 すべてをフルスクラッチするプログラミングの方向性は必ずしも得策じゃないよ 既存のライブラリやコンポーネントを上手く利用するのもOOPの要素なんだよ。 OOPで継承を用いた設計について調べてみた。(OOP理論の入門ではなく、 継承を用いた設計などが入った解説) この連載は良いかもしれない。 オブジェクト指向プログラミング超入門 .NETでオブジェクト指向プログラミングを始めよう http://www.atmarkit.co.jp/fdotnet/basics/oop_index/index.html 特に第6回は、今まで出てきていた話題だと思う。 Objectクラスで仮想メソッドToStringをもち、それから派生したクラスは、 オーバーロードをする仕組みを図説していて分かりやすい。 第6回 階層の頂点に立つクラス http://www.atmarkit.co.jp/fdotnet/basics/oop06/oop06_01.html >>250 PHPのプログラマにも非常に参考になると思いますよ。 .NETの世界はクラスベースなので初めからOOPの思考で実装します。 関数が作れないので構造化思考のVB6プログラマとか、クラスをnewせずに 引数を大量に渡すスタティックメソッドを呼んだりしてしまいます・・・ PHPはC言語での関数モジュールを呼び出す実装スタイルに近いので やはりクラスを使って構造化プログラミングをしちゃいがちですね。 普及しているPHP4がOOP対応不十分なのと、開発環境が貧弱であることも PHPでOOPがなかなか利用されない原因になってたりしますよね。 プロテクテッドメソッドの概念とかIDEがないと、なんでそうするのか なかなか理解出来ないとも思いますしね。 いくらかのデータを登録し、その内容を検索するWebシステムで使用する クラス構成で、Viewに絞った構成を考えてみた。 [View] ├[認証] ├[個人情報入力] ├[メニュー] ├[検索指定] ├[検索結果] 別の案として、[View]から[Input View]と[Output View]の 二つを継承し、さらに以下のような継承も浮かんだけれど、 継承して分ける必要性は無さそうなので、上記の方が良いように思う。 [Input View] ├[認証] ├[個人情報入力] [Output View] ├[メニュー] ├[検索指定] ├[検索結果] >>252 [View] ├[LoginView] ├[InsertView] ├[MenuView] ├[SelectView] ├[ResultView] こんな感じ? Debug用出力のメソッドをView(基底クラス)に追加するといいだろうね。 各画面([LoginView] [InsertView] [MenuView] ・・・)で エラー確認用のメソッドをオーバーロードする形で。 開発中はPOSTで受け取ったデータとかを画面上部に表示しながら動作確認する っていうのは、よくやるからね。 Objectクラスを継承する形にするのは、このスレでは共通したメソッドの 実装という理由だ。という話だったけど、リファレンス関係の処理で 便利だという話がサイトに載っているようだね。 このあたりの考え方も活かすと良いかもしれない。 ただ、PHPのOOPだとうまく実装出来ないかもしれないが。 >>207-209 >>250 Modelクラスも以下のメソッドを追加するという感じで設計すると良いのかな。 Select // データ取り出し Delete // 削除 Insert // 新規追加 Update // 既存データの更新 >>228 に載ってる既存のクラスには Execute があるけれど、 これも残しておくべきかな? 案がいくつか出てきたので、前回の駄目なソースを破棄して またソースコードをリニューアルしようかと思ったが、 いざやり始めてみると、データベースを管理する基底クラスの 設計を具体的にどうするかをきめないといけなくなり、それを どうするかで迷っている。。。 概ね以下のような感じにしたいと思ってるんだけどね。 DB格納の基底クラス:CFDB テキストファイルに保存するクラス:Text_DB extend CFDB PostgreSQLに保存するクラス:PostgreSQL_DB extend CFDB MySQLに保存するクラス:MySQL_DB extend CFDB で、この3つのいずれかのインスタンスを Model のメンバに持たせる。 現在のコード(CFModelのメンバ) var $file_name; // 読み込むファイル名 更新案のコード var $m_db; // データベースを格納。 >>255 普通は機能をメソッドに振り分けると思うけど コントローラのメソッド内で以下の様に 操作出来たら面白くない? // モデルにフォーム値を渡してデータ書き込み $insert = $this->models['InsertModel']; $insert->setItem('name', $_POST['name']); $insert->setItem('title', $_POST['title']); $insert->setItem('body', $_POST['body']); $insert->execute(); // ビュー表示用にデータをロードする $select = $this->models['SelectModel']; $data = $select->execute(); >>256 自分なりに試行錯誤で機能を実装してみるのも楽しいかもね。 誰か>>252 のアプリ作成に必要な要求仕様作ってよ。 >>257 要求仕様案 私は眼鏡屋(○○支店の店長)をやっている。 顧客の情報(名前、住所、性別、生年月日、・・・)を管理したい。 ・眼鏡を購入した顧客の情報を登録しておき、ある一定期間経つと 新しい眼鏡を購入する案内のDMを発送したい。 →条件検索をしたい。 ・登録した情報を検索し、どんなお客様かをすぐに確認出来るようにする。 →例えば、苗字を聞いて、詳細が分かるようにする。 ・眼鏡の定期的なメンテナンスで、訪問してきたら、その対応履歴を 登録しておきたい。 →眼鏡のクリーニング、シリコンパッド(鼻にあてるやつ)の交換など ・定期的なメンテナンスは無料であるので、全く店に来ない客には、 その無料案内のDMを発送したい。 →今回は、複数の店舗にまたがった処理はいらない。 ・他の社員に勝手に情報を触られないように、認証を通すようにする。 眼鏡の在庫管理は、このシステムとは別。 これは、プログラムの規模が大きくなりすぎるようであれば、 もちろん内容を変えてもいいです。「顧客の情報を登録し、 それを検索する」という流れだと、勉強用サンプルとして非常に 良いのでは、と思いました。 [データの入力例] 氏名:茂名 フリガナ:モナー 性別:男性 生年月日:H1/3/3 住所:東京都・・・ コメント:ふちなしタイプを希望している。 眼鏡購入日:2007/1/5 眼鏡の型番:2ch [2007/1/5に購入した2ch]のメンテナンス履歴 2007/2/5:クリーニング 2007/3/15:ネジの交換 2007/5/1:クリーニング、曲がったフレームの修正 顧客のデータ1件に、眼鏡の購入日がつながり、さらに、メンテナンス履歴が つながる構成になるけれど、今回は勉強用なので、「顧客のデータ1件=眼鏡の購入日1件」 としてもいいかもね。 再度購入したら、顧客の個人情報を0から入力しなおすみたいな。 View の Debug メソッドの仕様もどうするかで迷っている。 Execute($param)したあと、Debugとか、もしくは、 Debugの中でExecute($param)を呼び出す処理だと、 <html>タグのそとに確認データが出力されてしまう。 Debug モードを on にすれば、<body>タグの上部に テーブルで区切ってデータが表示されるとかかな。 だったら、メンバにDebugモードを追加かな。 という感じに考えてる。 みんなどう思う? >>258 ちょっとしたシステムじゃん・・ (´・ω・) それこそ既存のフレームワーク使用する案件だよ。 >>260 ディレクティブ付けたechoやvar_dump埋め込みで十分だと思うよ。 むしろその機能を実装するより、デバッガ環境構築した方がいい・・・ OOPに対する基本的概念への理解があまりにも無さ過ぎると思うんだ。 >>255 にしても、Executeメソッドに呼ばれる仕組み作ってんのに、 なんで新しいメソッド実装して直接呼びたがるんだろう? あれほどインタフェイスだけで実装するんだと(ry それよりコントローラの実装仕様どうするの? >>243 >ttp://www.geocities.jp/narutobakijp2/ ↓動作サンプルを設置しました。 http://ssurl.net/so2o ↓コードに関するコメントのまとめ(>>184-226 辺り) http://ssurl.net/h8bu >>262 非常に乙です。m(_ _)m >>226 だけど >>1 さんにここまでやって貰っちゃって申し訳ないし これぞOOPってサンプルを必死に実装してアップするんでしばしお待ちを・・ >>263 はやくアップしろよなw 俺がそれ見て勉強して、いつかエロイ人になったら お前を雇ってやるよ! 感謝しろ >>262 動作サンプルまでつけていただいて、ありがとうございます。 過去ログも、そのままコピペするんじゃなくて、色をつけたり 分類したりすると非常に分かり易いですね。 ShiftJISだったりとか、スペース2個というのは標準じゃないとかは 気づいてたのですが、そこまで治していただいて申し訳ないです。 >>266 別にわかんなくったって、やってけるから大丈夫。 無理に背伸びする必要は無い。 フレームワークの解説に関するサイトを見つけました。 ここで概要をつかんだ後、実際に触れてみるといいかもしれない。 ASP.NET vs. Struts フレームワーク徹底比較[前編] http://www.atmarkit.co.jp/fdotnet/special/aspstruts01/aspstruts01_04.html この文章書いてる人、ネットワーク関連の書籍でよく見かけるよね。 >>261 > OOPに対する基本的概念への理解があまりにも無さ過ぎると思うんだ。 > >>255 にしても、Executeメソッドに呼ばれる仕組み作ってんのに、 > なんで新しいメソッド実装して直接呼びたがるんだろう? > あれほどインタフェイスだけで実装するんだと(ry ちいたんのフレームワークは、Modelにinsertやdelを持ってるからそれを 参考に設計してみたんだけど。 ttp://php.cheetan.net/manual/model.php 俺はこれから勉強していくところなので理解がないのは認めるが、 このあたりはどういう見解なのかを教えて欲しい。 今回作るMVCフレームワークは、学習用なのでもっと簡潔な レベルなのを想定しているとか、ちいたん作っている人がOOPに 関する理解が無いだけだとか。 >>269 フレームワーク実装に正解も不正解も無いと思うけどね・・ 例えば ・クラスを使った構造化的メソッド呼び出し $model->insert(); $model->del(); よりも ・ポリモーフィズム $insert->execute(); $del->execute(); のほうがインターフェイスが規定されていて 簡潔で安全だと説明したかったんだよ。 insertメソッドやdelメソッドを呼ぶ文脈が規定されていたらどう? insertオブジェクトのexecuteメソッドならオブジェクトが 文脈をコントロール出来るでしょ? どうかな? 学習用だからこそ『呼ばれる仕組み』で実装しようとしているんだよ。 >>270 レスサンクス。となると、 class CInsert extend CView、class CDel extend CView、・・・ みたいな設計にするということ? ちょっと大雑把になってるけど、CInsertはこんな感じに実装するとか。 (テーブルのフィールドは、a,b,cという場合。) class CInsert extend CView{ var $field_a; var $field_b; var $field_c; function setItem($field, $data){ if($field == "a"){ $field_a = $data; } if($field == "b"){ $field_b = $data; } if($field == "c"){ $field_c = $data; } } function _OnExecute($param){ $fp = fopen($file_name,"a"); $write_line = $field_a . "," . $field_b . "," . $field_c; fwrite($fp,$write_line); fclose($fp); } } じゃ、用件仕様はこんな感じで良いのか? [認証] →・ID、パスワードにて認証 ・認証成功で[メニュー]へ移動 [メニュー] →・(新規)[個人情報入力]、[検索指定]画面へ移動するボタンがある [個人情報入力] →・名前、性別 を登録 [検索指定] →・氏名のキーワードを含む検索、性別指定が出来る。 [検索結果] →・条件に一致するデータを一覧で出す。 ・個人情報を修正したい場合は、ここから[個人情報入力]へ移動する。 ・個人情報を削除したい場合は、ここで削除ボタンを押す。 >>271 今こんな感じ。 [DataModel.php] <?php /** * データModel抽象クラスです。 */ class DataModel extends Model { # @access private var $_items; # @access public var $file_name; # @access public function setItem($key, $value) { $this->_items[$key] = $value; } # @access public function getItem($key) { return $this->_items[$key]; } } ?> [InsertModel.php] <?php /** * データ追加Model抽象クラスです。 */ class InsertModel extends DataModel { # @access sealed function & _onExecute(&$param) { return $this->_OnInsert(&$param); } # @access protected function & _onInsert(&$param) { trigger_error('オーバーライドして下さい。', E_USER_ERROR); } } [SampleInsertModel.php] <?php /** * データ追加 サンプルクラスです。 */ class SampleInsertModel extends InsertModel { # @access protected function & _onInsert(&$param) { // ここで初めてユーザ定義のメソッドを実行する。 // FWからここが呼ばれるまで待ってるのがポイント! // INSERTイベントの処理ハンドラに記述するともとれるね。 return $this->_saveData(); } /** * ユーザ定義のプライベートメソッド */ # @access private function _saveData() { // リクエストは以下のインターフェイスで取得。 $value = $this->getItem('hoge_data'); // ここで初めてHogeHogeする。 // DBオブジェクト呼ぶなりご自由に! return $data; } } ?> 細かい指摘になるけれど、継承関係の勉強中なので質問で書き込みします。 [InsertModel.php] class InsertModel extends DataModel function & _onExecute(&$param) のところは、 return $this->_OnInsert(&$param); となっているけれど、 return $this->_onInsert(&$param); が正しいという解釈で良いのですよね? >>273-275 ソースのサンプルサンクス。 イメージしてたよりも継承が多いですね。 全体ソースコードの可読性よりも、クラス単位での 再利用性を考えた場合は、このような構成になる のでしょうね。早く慣れないといけません。 まだ中身が出来ていない状況なので、修正の必要はあるだろうけど、 こんな感じでドキュメントもまとめていくと、分かりやすくなるだろうね。 ■SampleInsertModelクラス[SampleInsertModel.php] Model - DataModel - InsertModel - SampleInsertModel ◎概要 DBへのデータの記録、読み取りを行うクラス。 ◎メンバ一覧 [publicコンストラクタ] SampleInsertModel() [publicメソッド] setItem($key, $value):setter。フィールド名を指定し、データを登録する。 getItem($key):getter。フィールド名を指定し、データを取得する。 Execute($param):setItemでセットしたデータをDBに記録する。 ◎使用例 $model = new SampleInsertModel(); // クラスのインスタンスを生成する。 $model->setItem('Name', 'Tarou'); // [Name]フィールドに[Tarou]を登録する。 $model->setItem('Sex', 'man'); // [Name]フィールドに[man]を登録する。 $model->Execute(); // setItemで登録したデータをDBに書き込む。 >>263 ひとまず出来ました・・疲れました・説明は後でアップしようと思います・・ ttp://proxy.f3.ymdb.yahoofs.jp/bc/4525b767_dfac/bc/452a/PHP%a5%d5%a5%ec%a1%bc%a5%e0%a5%ef%a1%bc%a5%af.zip?BCUjxqHB4brtVvJJ >>279 乙です。じっくりソースを読んでみます。 せっかくプログラムを作っていただいたのだから、みんなでその説明文章をまとめるといいかもね。 例えば、こんな感じでhtmlで書いておいて、ファイル名をクリックすると、その詳細の説明のページに飛ぶとか。 [abstract] [controls] 空 [models] DataModel.php、DeleteModel.php、InsertModel.php、SelectModel.php、UpdateModel.php [views] HtmlQuickFormSmartyView.php、RenderView.php [controls] MainControl.php、SkeletonControl.php [data] 空 [framework] Base.php、Control.php、Model.php、View.php [lib] Request.php [models] SampleInsertModel.php、SampleSelectModel.php、SkeletonSelectModel.php [smarty] [cashe] 空 [templates] index_tmple.html、output_tmple.html [templates_c] 空 [views] HtmlQuickFormSmartyIndexView.php、HtmlQuickFormSmartyOutputView.php IndexView.php、OutputView.php、SkeletonView.php app.log、appconf.php、csv.txt、hoge.txt、index.php、Main.php、userconf.php >>281 >>279 ですがphpDocumentorで今作っているのでちょっと待っててね。 phpDocumentorにソース読み込ませて吐かせただけです。 ttp://proxy.f3.ymdb.yahoofs.jp/bc/4525b767_dfac/bc/452a/PHP_FW_DOC_01.zip?BCKv5qHBVNsncE.h フォルダ内のindex.htmlです、荒いですがご容赦を。 とりあえずトライアルなんでまだリファクタ出来そうだけど・・ [コントローラの処理] _form_onLoad _buttonHoge_onClick [モデルの処理] _onSelect _onInsert [ビューの処理] _onRender 上記のイベントハンドラにユーザ処理を記述して フレームワークに呼んでもらう構造になってます。 >>216 を実装したつもりです・・・ 有名なハリウッドの法則です。 [カプセル化]は良いとして、やはり[継承]と[ポリモーフィズム]を うまく使うのは最初難しいかもしれない・・ これらの実装もデザパタとしてライブラリ化されたものに過ぎないけどね。 OOP FW ソース ttp://proxy.f3.ymdb.yahoofs.jp/bc/4525b767_dfac/bc/452a/OOP_FW_02.zip?BCE07qHBz_6Z6R84 OOP FW ドキュメント ttp://proxy.f3.ymdb.yahoofs.jp/bc/4525b767_dfac/bc/452a/OOP_FW_DOC_02.zip?BCE07qHB2C3Z36pC すいません再アップしました、ドキュメントにControlが反映されてませんでした。 全体構成の把握はまだ出来てないけれど、只今、ソース解析中・・・ いちゃもんつけるつもりじゃないけれど、気になった点を2つ。 Control.phpのPOSTされたSubmitボタン名取得のところは クラス化されてないのはどうしてなのでしょうか? さらに非常にクラスが多くなって面倒になるから? class Control extends Base var \$_view_calss; このメンバはあえてclassにしてない理由はあるのでしょうか。 >>287 POSTされたサブミットボタン名取得部分は説明の通りです・・ 今その部分をC#でのデリゲートで実装しようと思ってます。 Viewクラスexecuteのところもこのままでは$eパラメータが コントローラから任意に渡せないので検討中です。 オブジェクトにexecute以外のパブリックメソッドを 実装しないのが目標です・・(※アクセサ以外) クラスの継承関係が結構複雑になってますね。 Documentsいただいても、追いかけていって、全体構造を把握するのが結構大変。 例えば、SampleInsertModelからその元を追っていくと、以下のような継承構造。 Base - Model - DataModel - InsertModel - SampleInsertModel 俺のメモとして、SampleInsertModelを追いかけていった様子をまとめておく。 ■Base(抽象)クラス[fw/framework/Base.php] ●パブリックメソッド & execute(&$param, $e) →アプリのログを記録する。_onExecute(&$param, $e)を実行 ●プロテクテッドメソッド _onExecute(&$param, $e) →サブクラスでオーバーライドして使用。 ■Model(抽象)クラス[fw/framework/Mode.php] ●プロパティ $src_file_name; // 読み込むファイル名 $dst_file_name; // 書き込むファイル名 ■DataModel(抽象)クラス[fw/abstract/models/DataModel.php] ●フィールド $_items; // コントロール値のハッシュを保存 ●パブリックメソッド setItem($key, $value) // コントロール値を受け取り、$_itemsに代入 getItem($key) // $_itemsの値を返す。 ■InsertModel(抽象)クラス[fw/abstract/models/InsertDataModel.php] ●シールドメソッド & _onExecute(&$sender, $e) →onInsert(&$sender, $e) ●プロテクテッドメソッド & _onInsert(&$sender, $e) →オーバーライドして使用する。 ■SampleInsertModelクラス[fw/models/SampleInsertModel.php] ●プロテクテッドメソッド $ _onInsert(&$sender, $e) →ここにユーザ定義のコードを記述する。_saveData()を実行 ●プライベートメソッド _saveData() →現在未実装。 こうやってみてみると、クラスを継承する際の設計思想が見えてくるな。 どの段階で実装を替えるかを考えた場合、どのクラスを置き換えれば良いかも分かる。 しかし、俺はこれまでフレームワークの構成などをじっくり読んだりしたことが無いので、 つい、ここまでクラスを継承させるメリットがあるのかなとか思ってしまう。 なんか、1つのメソッドを実装するのに、1回継承してるって感じだよね。 例えば、Model(抽象)クラスの $src_file_name を別のものにする場合、 それ以降のクラスが全部影響するかの確認が必要なわけだから、 Model(抽象)クラス以降のものをすべて一つのクラスにまとめて書いても 同じなんじゃないかと思えてしまう。 こういうのとは別な場面で、継承しているメリットがあるってことかな? ちょっと紹介しておきますね。 フレームワークを使った開発のメリット、デメリットを教えてください http://q.hatena.ne.jp/1188498291 特集:第1回 フレームワーク「Struts」の基礎を知る (3/8) フレームワークのメリットとデメリット http://www.itmedia.co.jp/enterprise/0310/06/epn03_3.html Control の & _onExecute(&\$param, \$e) で \$this->_view_calss = \$view_calss; というコードがあるけれど、右辺の \$view_calss って、 何処でも定義されてないですよね? このまま動かすと、nullが入るだけのように思えるんだけど。 Viewクラスの継承関係で、かいつまんだ一覧を書いておきます。 個別にはDocに書いてはあるけれど、こういう書き方みると分かりやすくない? Base - View - RenderView - IndexView ■Base(抽象)クラス[fw/framework/Base.php] (省略) ■View(抽象)クラス[fw/framework/View.php] ●プロパティ $post_file; // POSTするファイル名 ■RenderView(抽象)クラス[fw/abstract/views/RenderView.php] ●プロテクテッドメソッド & _onExecute(&$sender, $e) // _onRender(&$sender, $e)を呼ぶ & _onRender(&$sender, $e) // サブクラスにてオーバーラードする。 ■IndexViewクラス[fw/views/IndexView.php] ●コンストラクタ $this->post_file = 'index.php'; ●プロテクテッドメソッド & _onRender(&$sender, $e) // オーバーライド →html出力する。テキストボックスと送信ボタン >>293 1行上のフックハンドラ実行の結果を渡している。 ロードメソッド[MainControl::_form_onLoad(&$sender, $e)]が(POSTパラメータが 無い場合に呼ばれるメソッド)呼ばれるまでの経緯をたどってみたが、非常に複雑だ。。。 [fw/index.php]が実行される。 Mainクラスのインスタンスが生成され、execute(&$app, $e)が実行される。 Base:: & execute(&$param, $e) にて、 Base:: & _onExecute(&$param, $e)が実行される。 これは、Main::execute(&$app, $e)にてオーバーライドされている。 Controlクラスのインスタンスが生成され、execute(&$app, $e)が実行される。 Base:: & execute(&$param, $e) にて、 Base:: & _onExecute(&$param, $e)が実行される。 これはControl:: & _ onExecute(&$param, $e)にてオーバーライドされている。 Control:: & _onExecute(&$param, \$e) にて、Control::_hookedUpControler(&\$sender, \$e)を呼び出す。 Control::_hookedUpControler(&\$sender, \$e) にて、Control::_form_onLoad(&$sender, $e)を呼ぶ。 これはMainControl::_form_onLoad(&$sender, $e)にてオーバーライドされている。 MainControl::_form_onLoad(&$sender, $e) が実行される。 継承関係 Base - Control - MainControl Base - Main >>298 見れるはずですが・・以下はどうですか? Eclipceでのデバッグ画面です ttp://proxy.f3.ymdb.yahoofs.jp/bc/4525b767_dfac/bc/452a/OOPFW_DEBUG.jpg?BC3YDrHBI.a6ljXl >>298 どうでしょうか? ttp://briefcase.yahoo.co.jp/bc/oopfw これは、>>1 さんのサイトでは、「入力フォームを作ってみる」とは 別で、「フレームワークを作ってみる」の演習という位置づけにした 方がいいかもしれないね。 これからの流れとしては、上のほうにあるように、このソースを 解読・改変していくための補助ドキュメント作成の方向と、 このフレームワークを使ってみる人のためのドキュメント作成 (チュートリアルみたいなもの)になるだろうね。 出来る範囲でみんなで手伝っていってみましょう。 このフレームワークは、MFCみたく、あらかじめ準備された クラスのメソッド中に書き加えていくスタイルなのかな? それとも、VBみたいにそういうソースコードを全部隠蔽 してしまう方向でいくのかな?ちょっと気になった。 こうやってソースを読んでみると、これまで抽象的に聞いていた フレームワークを使ったプログラミングのメリットとデメリットが実感できるね。 今まで、システムを組む際はOOPやフレームワークを使う方向にするべきだと 思ってたけれど、そうでもなく、状況や目的に合わせて選択する というのが良い事が分かってきたような気がする。 小規模で全体概要を把握したいとか、移植性を考える場合は、フレームワークよりも、 クラスライブラリを使うスタイルの方が良い場合もありそうだ。 MVCでフレームワークを自作する方向と、クラスライブラリを自作する方向の 2つの方向をやってみて、それぞれのメリットとデメリットを確認していけば、 システムを作る場合の検討材料に出来ると思う。 何でもフルスクラッチしていき、なるべく依存性は無いようにし、(言語の バージョンくらいに収めるとか)その組み合わせでアプリを作る、みたいな。 再度リファクタしてみました。 ttp://briefcase.yahoo.co.jp/bc/oopfw [Controlクラス] ・リクエストオブジェクトの参照の重複の削除 ・サブクラスでのフックハンドラ処理修正 ・Viewオブジェクトの実行方法修正 ※これはViewオブジェクトハンドリングの自由度をました反面、 ユーザからの取り回しが煩雑になったかもしれませんね・・ [Modelクラス] ・継承関係の見直し、ItemBaseクラスの導入などです・・ MVCの継承関係が美しくないですが・・ >>291 リファクタしながら構成を練っていってますが 継承クラスでの責任が小さい単位で分割されていると 大きく修正が入った時も楽だと思います。 >>303 MFCもVB6もフックハンドラに処理を記述していく方式なので それを参考にしています、サンプルFWも自由にいじってもらって 参考にしてもらえたら良いと思います。 >>305 クラスライブラリ方式もいいかもしれないですね。 フレームワークのメリットとデメリットにおいて、なるべく具体例を書いた形でまとめてみた。 【メリット】 1.ビューとロジックの切り分けが出来る。(共同作業時に便利) http://www.atmarkit.co.jp/fdotnet/aspandvs/aspandvs01/aspandvs01_01.html 2.定型的なコードを何度も書かなくてよくなる。 例えば、ASP.NETでは、POSTの値を取得して・・・などの事を考えなくて良い。 テキストボックスやボタンも、画面にドラッグするだけ。 3.ソースコードが自動的にフレームワークの規約に従った記述方法となり、 全体的な処理構成が把握しやすく、メンテナンスが楽になる。 例えば、構造化プログラミングならば、まず全体構成(どの関数がどんな役割を 持っているかなど)を把握し、そこから問題部分を探すことになる。 フレームワークの場合は、まずはこのイベントハンドラの部分を見れば良いなという事が分かる。 【デメリット】 1.フレームワーク自体の使い方を学ばなければならない。 ・言語の基本ルールとは異なった、フレームワーク特有の記述方法があるため、すぐに組めない。 ASP.NETでは、IsPostBack の概念を学ばなければならない。 http://www.atmarkit.co.jp/fdotnet/dotnettips/043postback/postback.html ちいたんでは、function action( &$c )とか、$c->という書き方と機能を把握しなければならない。 http://php.cheetan.net/manual/tutorial.php ・フレームワーク自体にも得手・不得手など特徴があり、それを把握しなければならない。 ASP.NETはIISが必要な為、自動的にサーバOSはWindowsが必須となり、依存性がある。 ASP.NETとStrutsの比較は、以下のサイトを参照 http://www.atmarkit.co.jp/fdotnet/special/aspstruts01/aspstruts01_01.html 2.フレームワーク自体に問題があると対処が困難。 例えば.NET Framework のバグは、開発元の不具合修正を待つしかない。 オープンソースのフレームワークであっても、ソースコードが大量な為、把握が出来ない。 read.cgi ver 07.5.5 2024/06/08 Walang Kapalit ★ | Donguri System Team 5ちゃんねる