Upload
hiraku-nakano
View
2.322
Download
4
Embed Size (px)
DESCRIPTION
PHP勉強会で発表した内容です
Citation preview
PECL-AOPの紹介
@Hiraku
自己紹介 @Hiraku( 中野 拓 ) Web プログラマやってます PHP 歴 4 年
http://blog.tojiru.net/ https://github.com/hirak
AOP のてきとーな解説
Wikipedia 先生の解説
アスペクト指向プログラミング Aspect Oriented Programming
オブジェクト指向ではうまく分離できない特徴(クラス間を横断 (cross-cutting) するような機能)を「アスペクト」とみなし、アスペクト記述言語をもちいて分離して記述することでプログラムに柔軟性をもたせようとする試み。
具体例 例外処理 関数キャッシュ ロギング トランザクション 実行時間の計測
etc..
例外処理
try { doSomething(); //…
} catch (OutOfBoundsException $e) { recoverError($e);
} catch (RangeException $e) { recoverError($e);
}
class A { function a() { try { doSomething(); //… } catch (RuntimeException $e) { processError($e); } } function b() { try { doSomething(); //… } catch (RuntimeException $e) { processError($e); } } function c() { try { doSomething(); //… } catch (RuntimeException $e) { processError($e); } }}
よくある光景
例外処理の問題 いくらエラーの回復処理を関数化して
も、 try ~ catch ブロック自体は何度も書くことに
DRY(Don't Repeat Yourself) じゃない 「これ、さっきも書いたコードだな
…」
クラス分割や関数分割だけだとうまくモジュール化できないもの
横断的関心事= Aspect
こういうパターンが多い function a() { try { doSomething(); //… } catch (RuntimeException $e) { processError($e); } }
try { //…} catch (RuntimeException $e) { processError($e);}
function a() { doSomething(); //…}
こう分割できたらいいのに…
pecl-AOP の概要
pecl-AOP
AOP を extension によって実装したもの
http://pecl.php.net/package/AOP
インストールさえできれば文法はわかりやすい
runkit っぽい
# pecl install aop-beta
AOP 用語 (pecl-AOP の場合 ) Advice
Aspect をモジュール化したもの。 pecl-AOP ではコールバック関数で実装
JoinpointAdvice を織り込める場所。
weaveAdvice を Joinpoint に差し込むこと。
例外処理を Advice 化function processError(AopJoinpoint $joinpoint) { try { return $joinpoint->process();
} catch (RuntimeException $e) { // エラー処理
}}
Weave( 織り込む )aop_add_around('A->*()', 'processError');
A クラスのすべてのメソッドに processError() を織り込む、という指令
これで A クラスのすべてのメソッドは、 processError 経由で呼ばれるようになる
class A { function a() { try { doSomething(); //… } catch (RuntimeException $e) { processError($e); } } function b() { try { doSomething(); //… } catch (RuntimeException $e) { processError($e); } } function c() { try { doSomething(); //… } catch (RuntimeException $e) { processError($e); } }}
class A { function a() { doSomething(); //… } function b() { doSomething(); //… } function c() { doSomething(); //… }}
aop_add_around('A->*()', function (AopJoinpoint $joinpoint) { try { return $joinpoint->process(); } catch (RuntimeException $e) { // エラー処理 }});
DRY になったね!
対応 Joinpoint
before any method / function call after any method / function call around any method / function call During the arousing of an exception
of any method / function after any method / function call,
should the method terminate normally or not (triggers an exception or not)
応用例はいっぱいありそう 例外処理 関数キャッシュ 入出力のフィルタリング ロギング トランザクション 実行時間の計測
etc..
関数キャッシュ 関数自体にキャッシュシステムを組み込む
add_aop_around('A->*()', function (AopJoinpoint $joinpoint) { $key = $joinpoint->getClassName() . '->' . $joinpoint->getMethodName(); $cache = apc_fetch($key, $success);
if ($success) { return $cache; }
$result = $joinpoint->process(); apc_store($key, $result);
return $result;});
もっと応用(pecl-AOP に限った話 )
pecl-AOP のヤバいところ 既存の関数やメソッドなら何でも置き
換え可能
テストのモックとして強力
rand() の固定化
rand() を同じ値しか返さない関数で置換 何度実行しても 0 を返す
aop_add_around('rand()', function () { return 0;});
var_dump(rand());var_dump(rand());var_dump(rand());
time() の固定化
time() も初期値を自由に変更できる
201X 年を再現する、ということが可能timecop の方が特化してて便利だけど…
それに近いことが可能https://github.com/hnw/php-timecop
aop_add_around('time()', function () { return 0;});
var_dump(time());
何でも置き換え WebAPI にリクエストする部分を固定
化とか DB に接続する部分を固定化とか
要はクラスの継承と無関係な継承・上書きが可能
自由すぎてわけわからん
超強力 & 凶悪
まとめ
pecl-AOP 面白いよ 超強力 & 凶悪
テストのお供に 書きにくいコードをすっきり DRY に
PHP のゆるさが5割増しになるのが悩ましい
注意点 まだ beta 扱いです。 インストールもこけたりテストもこけ
たりする segmentation fault もよく起きる
実戦投入はまだ危険