Web技術勉強会 20100925

44
WEB技術勉強 技術勉強 技術勉強 技術勉強 RYUICHI TANAKA 再びのPHPでオジェク指向ググ

description

 

Transcript of Web技術勉強会 20100925

Page 1: Web技術勉強会 20100925

WEB技術勉強会技術勉強会技術勉強会技術勉強会RYUICHI TANAKA

再びのPHPでオブジェクト指向プログラミング

Page 2: Web技術勉強会 20100925

2年前を振り返ってみる

Page 3: Web技術勉強会 20100925

PHPでオブジェクト指向

� 2年ほど前に挑戦している

� http://www.slideshare.net/mapserver2007/web5sli

de-share

� http://www.slideshare.net/mapserver2007/web11-� http://www.slideshare.net/mapserver2007/web11-

presentation

� 今見るとさすがにいろいろ足らないところがある…。

Page 4: Web技術勉強会 20100925

OOPを導入した自作ブログ

� 2008年10月くらいから開発開始

� 現在は開発終了して稼働中

� http://summer-lights.jp/diarysys4

� 主要機能はすべてクラス化� 主要機能はすべてクラス化

� 自作のテンプレート機構

� MVCを意識

Page 5: Web技術勉強会 20100925

ディレクトリ構造(一部抜粋)

� /

� css/

� php/

� func/ ... 関数群� func/ ... 関数群

� class/ … クラスファイル群

� load.php … 通常の受信処理を一括処理

� ajax.php … Ajaxの受信処理を一括処理

� tmpl/

� index.php

Page 6: Web技術勉強会 20100925

1. index.php(View)はController(load.php)に表示処理を依頼する2. load.phpはリクエストパラメータから判断して処理を開始する3. func/xxx.phpはModel(php/class)に処理を依頼する4. Modelは処理結果をControllerに返す5. Controllerは処理結果を加工してViewに返す6. Viewは処理結果を表示する

Page 7: Web技術勉強会 20100925

問題点(MVC)

� Contorollerが肥大化

� すべての処理をload.php, ajax.phpで一手に引き受けている=保守性低下

� Modelも肥大化� Modelも肥大化

� 個人的にはもう一層挟んだほうがスリム化すると思う

Page 8: Web技術勉強会 20100925

問題点(構造)

� ディレクトリ構造

� MVCではなく言語単位になっているので美しくない

� Controllerがクラス化されていない� Controllerがクラス化されていない

� 汎用クラスとdiarysys4専用Modelが混在

� 分けたほうが再利用性アップ

� ルールが弱い

� 必ず実装すべきメソッド定義がない

Page 9: Web技術勉強会 20100925

反省点を踏まえて反省点を踏まえて

再挑戦

Page 10: Web技術勉強会 20100925

改善(MVC)

� Modelよりコアな層を追加� Library層を追加。ModelはLibraryに対して

(ControllerがModelへ送るように)メッセージを送信する

� Libraryは原則的に汎用性を高くする� システム専用になる場合もあり

� Libraryの用途は3つ� DB処理

� 外部サービス処理

� その他汎用的処理

Page 11: Web技術勉強会 20100925

改善(MVC)

� Libraryはシステムのコアを操作するのでテストをきっちり行う

� Libraryにバグがなければそれを利用するだけのModelのバグもなくなる(はず)のModelのバグもなくなる(はず)

� Modelを利用するだけのContorollerのバグもなくなる(はず)

Page 12: Web技術勉強会 20100925

改善(MVC)

� 役割分担を明確に� Controller

� ロジックはかかない(分岐処理はOK)

� Modelを呼ぶかViewを描画するのどちらか

� Model� Model� システム専用のロジック(SQLなど)を書く� Libraryを呼ぶかControllerに値を返すのどちらか

� View� Controllerからの描画命令に従って描画するだけ

� Library� DB接続などコアな処理または外部リソースにアクセスする。汎用性を高めている。

Page 13: Web技術勉強会 20100925

改善(構造)

� ディレクトリ構造を見直し

� Railsを参考にContoroller、Model、View、Libraryディレクトリを作成

� 静的ファイルはすべてView扱い� 静的ファイルはすべてView扱い

� 処理はひとつのファイル(load.php)で一手に引き受けない

� 必要な処理ごとにContorollerをコールする

Page 14: Web技術勉強会 20100925

ディレクトリ構造

� /� controllers/

� ApplicationController.php … (抽象クラス)

� (各種処理ごとのController)

� models/( Model)� (各種処理ごとのModel)

� views/� images/

� js/

� lib/� DB.php

� DAO.php

� etc.

Page 15: Web技術勉強会 20100925

基本的な処理の流れ

� init.phpでContorollerをインスタンス化

� 各画面個別のContorollerをコール

� ContorollerはModelをコール

� Modelは必要ならLibraryをコール

� Libraryはメインの処理を実行し結果を返す

� Contorollerはlib/Template.phpをコールして結果を指定したテンプレートを表示する

Page 16: Web技術勉強会 20100925
Page 17: Web技術勉強会 20100925

デザインパターンデザインパターン

を適用

Page 18: Web技術勉強会 20100925

Singletonパターン

� Singletonパターンとは

� インスタンスが必ず1つしか生成されないことを保証する。

� 複数のインスタンスを作る必要がない場合は� 複数のインスタンスを作る必要がない場合はメモリの節約のために適用することがある

� 今回適用したクラス

� DB.php データベース接続クラス

Page 19: Web技術勉強会 20100925

DB.php

private $manager = null;

private function __construct() {}

protected function getManager($dbname) {

// ここでDB接続処理(PDO)

$manager = new PDO();$manager = new PDO();

return $manager;

}

ポイント:・コンストラクタはprivateで宣言・DB.phpは継承して使うのでインスタンスを返却するメソッド

(getManager)はprotectedで宣言

Page 20: Web技術勉強会 20100925

DAO.php

class DAO extends DB {

private static $dbaccessor = null;

private function __construct() {}

private function init() {} // 初期処理

public function getInstance() {

if (!is_object(DAO::$dbaccessor)) {

DAO::$dbaccessor = new DAO();

}

DAO::$dbaccessor->init();

return DAO::$dbaccessor;

}

// CRUDを処理するメソッドを以下に定義

}

Page 21: Web技術勉強会 20100925

DAO.php

� 使い方の例

$db = DAO::getInstance(); // (1)

$sql = “INSERT INTO …”;

$bind = array(“name” => “hirasawa_yui”);$bind = array(“name” => “hirasawa_yui”);

$db->insert($sql, $bind);

$db2 = DAO::getInstance(); // (1)と同じObj

// $db3 = new DAO(); // エラー

// $db4 = new DB(); // エラー

Page 22: Web技術勉強会 20100925

TemplateMethodパターン

� TemplateMethodパターンとは

� スーパークラスで処理の大枠を定義しておき、サブクラスで具体的実装を行う。

� 似たような処理だけど、微妙に違う複数� 似たような処理だけど、微妙に違う複数のクラスをまとめて処理したい場合に有効

� 今回の場合、外部サービス(Twitter、Blog、はてブなど)を一気に処理したかった

Page 23: Web技術勉強会 20100925

ServiceAbstract.php

� 外部サービスを処理するためのメソッドを定義。

� クラスはAbstract(抽象)クラスで定義

� 必須メソッドはabstractメソッドで定義� 必須メソッドはabstractメソッドで定義

� 具体実装をしてしまう場合(サブクラスで共通な処理)はprotectedで定義

� インスタンスから呼び出すメソッドはpublicで定義

Page 24: Web技術勉強会 20100925

ServiceAbstract.php

abstract class ServiceAbstract {

function __construct($params = array()) {

$this->prepare($params)

->fetch()

->process();

}}

final public function get() {

return $this->_data;

}

abstract protected function prepare($params);

abstract protected function fetch();

abstract protected function process();

Page 25: Web技術勉強会 20100925

ServiceBookmark.phpclass ServiceBookmark extends ServiceAbstract {

function __construct($params = array()) {

$this->_params = $params;

parent::__construct();

}

public function prepare($params) {

// ブクマデータ取得前処理

return $this;

}

public function fetch() {

// ブクマデータ取得処理

return $this;

}

public function process() {

// ブクマデータ加工

$this->_data = ...

}

Page 26: Web技術勉強会 20100925
Page 27: Web技術勉強会 20100925

使い方の例

$hatebu = new ServiceBookmark();

$data = $hatebu->get();

$twitter = new $twitter = new

ServiceTwitter($param);

$data2 = $twitter->get();

ポイント:

・異なる外部サービスの処理を同じにできる。

Page 28: Web技術勉強会 20100925

まとめて処理する

� リフレクションを使う

� リフレクションはクラスの内部情報が取得できたり、内部構造を書き換えたりすることができる。できる。

� 通常のクラスへのアクセス方法では不可能なことが可能(インスタンスからprivateメソッドを操作したり、定数を書き換えたり)

Page 29: Web技術勉強会 20100925

具体例

$services = array("Twitter", "Blog");foreach ($services as $service_name) {

$refClass = new ReflectionClass($service_name);

$service = $refClass->newInstance();

register($service->get());

}

ポイント:・文字列からインスタンスが生成可能・手続き方法が同じならループで一気に処理可能

Page 30: Web技術勉強会 20100925

今回こだわった点今回こだわった点

Page 31: Web技術勉強会 20100925

こだわったところ

� Contorollerは必ずApplicationControllerを継承する

� ApplicationController#render、ApplicationController#error はabstractで定義ApplicationController#error はabstractで定義し、サブクラスで必ず実装させる

� renderは画面描画、errorはエラー画面描画。これらはどんな画面でも必要なのでabstractにした

� 命名規則はRailsと同じ

Page 32: Web技術勉強会 20100925

こだわったところ

� リクエスト、セッションはModelで扱う

� $_GET, $_SESSIONのようにグローバルを直接

触れてしまうが、規則として直接触らないようにした。うにした。

� ApplicationControllerでリクエスト、セッショ

ンオブジェクトを生成し、サブクラスControllerで利用する。Modelに渡したい場合はController経由でインスタンスを渡す。

� 直接触ると値のValidationができないため

� 原則グローバル変数は使用禁止

Page 33: Web技術勉強会 20100925

こだわったところ

� DB処理

� DB.phpで接続処理,DAO.phpでCRUDの実行

� どちらもSingletonで実装

� DB.phpはインスタンスすら取得できない� DB.phpはインスタンスすら取得できない

� インスタンスが欲しければ必ずDAO.phpにアクセスしなければならない=DB接続を外部からさせない

� DAO.phpを定義することでPDOを抽象化

Page 34: Web技術勉強会 20100925

こだわったところ

� require処理

� phpのrequire/includeは実行中のファイルからの相対パス。厄介なのはInclude元のファイルからの相対パスになる点。からの相対パスになる点。

� 例:/index.phpで/class/Ajax.phpをIncludeしていて、Ajax.phpでrequrieするとき、開始位置は「/」になる(本当は/classになってほしい)

Page 35: Web技術勉強会 20100925

こだわったところ

� require処理

� どのファイルからrequire/includeをコールして

もかならずプロジェクトルートからの相対パスになるようにした=現在のディレクトリパスになるようにした=現在のディレクトリパスを考慮する必要がない

� 例:/ でも /class からでも

Common::import(“class/Ajax”)

でrequireされる。

Page 36: Web技術勉強会 20100925

こだわったところ

� Libraryのテストコードを作成

� SimpleTest(http://www.simpletest.org/)を使用

� symfonyなども利用しているテスティングフレームワークレームワーク

� Eclipse拡張あり(非常に良い)

� インストールが楽(requireするだけ。Eclipseで使う場合はそれすら不要)

� PHPUnitは非常に面倒+PHP4、PHP5で互換性なし

Page 37: Web技術勉強会 20100925

こだわったところ

� CSRF対策

� ワンタイムトークン方式で自前実装

� アクセスするたびにトークンが変化

� 間違ったトークンを渡すと更新できない� 間違ったトークンを渡すと更新できない

� 管理画面での内容更新で適用

Page 38: Web技術勉強会 20100925

こだわったところ

� 異なる外部サービスを同じ手続きで処理する設計

$services = array("Twitter", "Blog");

foreach ($services as $service_name) {

� 外から見ると同じ手続き(メソッド名)だが内部処理がすべて異なる処理を等価的に処理

� 条件分岐(if, switch)未使用

foreach ($services as $service_name) {

$refClass = new ReflectionClass($service_name);

$service = $refClass->newInstance();

register($service->get());

}

Page 39: Web技術勉強会 20100925

LifeStream

� 目的

� 自分の活動内容を一挙に集約すること

� 機能

作成したシステムへのゲートウェイ・リンク� 作成したシステムへのゲートウェイ・リンク

� 自分が行ったPOSTを管理

� Blog、Twitter、ブックマーク、その他サービス

� システム監視(外部非公開)

� ログ一括監視

� 障害監視、障害通知

Page 40: Web技術勉強会 20100925

トップページ(Portal)

Page 41: Web技術勉強会 20100925

プロジェクトページ(Project) :・過去に作ったシステムの説明とリンク

Page 42: Web技術勉強会 20100925

ログインページ(Login) :・はてな認証API+独自認証・デザインはあえてシンプルに

Page 43: Web技術勉強会 20100925

管理ページ(Management) :・プロジェクトページで表示する内容を制御・編集

Page 44: Web技術勉強会 20100925

開発してて思ったこと

� 他の言語の文化を学ぶことで得られるものがある� PHPにない流儀がJavaやRubyにある� PHPだけやってても気付けないことがある� PHPはある意味気軽にできる(環境構築が楽)� PHPはある意味気軽にできる(環境構築が楽)

� 使用できる言語をむやみに増やす必要はない� かえって混乱する、深さが足らなくなる� 適材適所

� テストがやりやすい言語を選ぶ� 結果的にPHPはやりにくい� プログラムを書き続けるとここに行くつく