pecl-aopの紹介
DESCRIPTION
PHP勉強会で発表した内容ですTRANSCRIPT
![Page 1: pecl-AOPの紹介](https://reader033.vdocuments.site/reader033/viewer/2022052901/556a52fad8b42a7a138b488b/html5/thumbnails/1.jpg)
PECL-AOPの紹介
@Hiraku
![Page 2: pecl-AOPの紹介](https://reader033.vdocuments.site/reader033/viewer/2022052901/556a52fad8b42a7a138b488b/html5/thumbnails/2.jpg)
自己紹介 @Hiraku( 中野 拓 ) Web プログラマやってます PHP 歴 4 年
http://blog.tojiru.net/ https://github.com/hirak
![Page 3: pecl-AOPの紹介](https://reader033.vdocuments.site/reader033/viewer/2022052901/556a52fad8b42a7a138b488b/html5/thumbnails/3.jpg)
AOP のてきとーな解説
![Page 4: pecl-AOPの紹介](https://reader033.vdocuments.site/reader033/viewer/2022052901/556a52fad8b42a7a138b488b/html5/thumbnails/4.jpg)
Wikipedia 先生の解説
アスペクト指向プログラミング Aspect Oriented Programming
オブジェクト指向ではうまく分離できない特徴(クラス間を横断 (cross-cutting) するような機能)を「アスペクト」とみなし、アスペクト記述言語をもちいて分離して記述することでプログラムに柔軟性をもたせようとする試み。
![Page 5: pecl-AOPの紹介](https://reader033.vdocuments.site/reader033/viewer/2022052901/556a52fad8b42a7a138b488b/html5/thumbnails/5.jpg)
具体例 例外処理 関数キャッシュ ロギング トランザクション 実行時間の計測
etc..
![Page 6: pecl-AOPの紹介](https://reader033.vdocuments.site/reader033/viewer/2022052901/556a52fad8b42a7a138b488b/html5/thumbnails/6.jpg)
例外処理
try { doSomething(); //…
} catch (OutOfBoundsException $e) { recoverError($e);
} catch (RangeException $e) { recoverError($e);
}
![Page 7: pecl-AOPの紹介](https://reader033.vdocuments.site/reader033/viewer/2022052901/556a52fad8b42a7a138b488b/html5/thumbnails/7.jpg)
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); } }}
よくある光景
![Page 8: pecl-AOPの紹介](https://reader033.vdocuments.site/reader033/viewer/2022052901/556a52fad8b42a7a138b488b/html5/thumbnails/8.jpg)
例外処理の問題 いくらエラーの回復処理を関数化して
も、 try ~ catch ブロック自体は何度も書くことに
DRY(Don't Repeat Yourself) じゃない 「これ、さっきも書いたコードだな
…」
![Page 9: pecl-AOPの紹介](https://reader033.vdocuments.site/reader033/viewer/2022052901/556a52fad8b42a7a138b488b/html5/thumbnails/9.jpg)
クラス分割や関数分割だけだとうまくモジュール化できないもの
横断的関心事= Aspect
![Page 10: pecl-AOPの紹介](https://reader033.vdocuments.site/reader033/viewer/2022052901/556a52fad8b42a7a138b488b/html5/thumbnails/10.jpg)
こういうパターンが多い function a() { try { doSomething(); //… } catch (RuntimeException $e) { processError($e); } }
try { //…} catch (RuntimeException $e) { processError($e);}
function a() { doSomething(); //…}
こう分割できたらいいのに…
![Page 11: pecl-AOPの紹介](https://reader033.vdocuments.site/reader033/viewer/2022052901/556a52fad8b42a7a138b488b/html5/thumbnails/11.jpg)
pecl-AOP の概要
![Page 12: pecl-AOPの紹介](https://reader033.vdocuments.site/reader033/viewer/2022052901/556a52fad8b42a7a138b488b/html5/thumbnails/12.jpg)
pecl-AOP
AOP を extension によって実装したもの
http://pecl.php.net/package/AOP
インストールさえできれば文法はわかりやすい
runkit っぽい
# pecl install aop-beta
![Page 13: pecl-AOPの紹介](https://reader033.vdocuments.site/reader033/viewer/2022052901/556a52fad8b42a7a138b488b/html5/thumbnails/13.jpg)
AOP 用語 (pecl-AOP の場合 ) Advice
Aspect をモジュール化したもの。 pecl-AOP ではコールバック関数で実装
JoinpointAdvice を織り込める場所。
weaveAdvice を Joinpoint に差し込むこと。
![Page 14: pecl-AOPの紹介](https://reader033.vdocuments.site/reader033/viewer/2022052901/556a52fad8b42a7a138b488b/html5/thumbnails/14.jpg)
例外処理を Advice 化function processError(AopJoinpoint $joinpoint) { try { return $joinpoint->process();
} catch (RuntimeException $e) { // エラー処理
}}
![Page 15: pecl-AOPの紹介](https://reader033.vdocuments.site/reader033/viewer/2022052901/556a52fad8b42a7a138b488b/html5/thumbnails/15.jpg)
Weave( 織り込む )aop_add_around('A->*()', 'processError');
A クラスのすべてのメソッドに processError() を織り込む、という指令
これで A クラスのすべてのメソッドは、 processError 経由で呼ばれるようになる
![Page 16: pecl-AOPの紹介](https://reader033.vdocuments.site/reader033/viewer/2022052901/556a52fad8b42a7a138b488b/html5/thumbnails/16.jpg)
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); } }}
![Page 17: pecl-AOPの紹介](https://reader033.vdocuments.site/reader033/viewer/2022052901/556a52fad8b42a7a138b488b/html5/thumbnails/17.jpg)
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 になったね!
![Page 18: pecl-AOPの紹介](https://reader033.vdocuments.site/reader033/viewer/2022052901/556a52fad8b42a7a138b488b/html5/thumbnails/18.jpg)
対応 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)
![Page 19: pecl-AOPの紹介](https://reader033.vdocuments.site/reader033/viewer/2022052901/556a52fad8b42a7a138b488b/html5/thumbnails/19.jpg)
応用例はいっぱいありそう 例外処理 関数キャッシュ 入出力のフィルタリング ロギング トランザクション 実行時間の計測
etc..
![Page 20: pecl-AOPの紹介](https://reader033.vdocuments.site/reader033/viewer/2022052901/556a52fad8b42a7a138b488b/html5/thumbnails/20.jpg)
関数キャッシュ 関数自体にキャッシュシステムを組み込む
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;});
![Page 21: pecl-AOPの紹介](https://reader033.vdocuments.site/reader033/viewer/2022052901/556a52fad8b42a7a138b488b/html5/thumbnails/21.jpg)
もっと応用(pecl-AOP に限った話 )
![Page 22: pecl-AOPの紹介](https://reader033.vdocuments.site/reader033/viewer/2022052901/556a52fad8b42a7a138b488b/html5/thumbnails/22.jpg)
pecl-AOP のヤバいところ 既存の関数やメソッドなら何でも置き
換え可能
テストのモックとして強力
![Page 23: pecl-AOPの紹介](https://reader033.vdocuments.site/reader033/viewer/2022052901/556a52fad8b42a7a138b488b/html5/thumbnails/23.jpg)
rand() の固定化
rand() を同じ値しか返さない関数で置換 何度実行しても 0 を返す
aop_add_around('rand()', function () { return 0;});
var_dump(rand());var_dump(rand());var_dump(rand());
![Page 24: pecl-AOPの紹介](https://reader033.vdocuments.site/reader033/viewer/2022052901/556a52fad8b42a7a138b488b/html5/thumbnails/24.jpg)
time() の固定化
time() も初期値を自由に変更できる
201X 年を再現する、ということが可能timecop の方が特化してて便利だけど…
それに近いことが可能https://github.com/hnw/php-timecop
aop_add_around('time()', function () { return 0;});
var_dump(time());
![Page 25: pecl-AOPの紹介](https://reader033.vdocuments.site/reader033/viewer/2022052901/556a52fad8b42a7a138b488b/html5/thumbnails/25.jpg)
何でも置き換え WebAPI にリクエストする部分を固定
化とか DB に接続する部分を固定化とか
要はクラスの継承と無関係な継承・上書きが可能
自由すぎてわけわからん
超強力 & 凶悪
![Page 26: pecl-AOPの紹介](https://reader033.vdocuments.site/reader033/viewer/2022052901/556a52fad8b42a7a138b488b/html5/thumbnails/26.jpg)
まとめ
![Page 27: pecl-AOPの紹介](https://reader033.vdocuments.site/reader033/viewer/2022052901/556a52fad8b42a7a138b488b/html5/thumbnails/27.jpg)
pecl-AOP 面白いよ 超強力 & 凶悪
テストのお供に 書きにくいコードをすっきり DRY に
PHP のゆるさが5割増しになるのが悩ましい
![Page 28: pecl-AOPの紹介](https://reader033.vdocuments.site/reader033/viewer/2022052901/556a52fad8b42a7a138b488b/html5/thumbnails/28.jpg)
注意点 まだ beta 扱いです。 インストールもこけたりテストもこけ
たりする segmentation fault もよく起きる
実戦投入はまだ危険