php フィールドインジェクションに挑戦する php勉強会2014
TRANSCRIPT
‹#›
The title of the presentation can go here, and it can span nearly the width of the page Company Proprietary and Confidential
PHP de フィールドインジェクション第84回 PHP勉強会 !竹澤 有貴
ytake
profile
• php, node.js, RDBMS, NoSQL • Laravel ユーザーグループ
• NewSQL • React.js がんばり中
https://www.facebook.com/yuuki.takezawahttps://twitter.com/ex_takezawa
竹澤 有貴 yuuki takezawa“
ytake
PHPでフィールドインジェクションって 要るの?
ytake
たぶん 要らない
ytake
まずは前提知識から
ytake
DI / Service Locater
• 明確な違い、わかりますか? • 似ているけど少し違う • PHP-DI • Aura.DI • Ray.DI • Orno\Di • Zend\Di • Symfony/DependencyInjection • Pimple • illuminate/container
違いは?“
ytake
コンテナから、 ある名前をキーに登録されたオブジェクトを取り出す
ytake
$container['db'] = function() { return new \PDO( 'mysql:dbname=tests;host=localhost', 'root', ‘root' ); }; var_dump($container[‘db’]());
ytake
インスタンス生成時に 必要なものをコンテナが渡してくれる
ytake
interface SomethingInterface{ public function perform();} class Something implements SomethingInterface{ public function perform() { return 'hello'; }}
ytake
class Perform{ public function __construct( SomethingInterface $something ) { $this->something = $something; } public function something() { return $this->something->perform(); }} new Perform(new Something);
ytake
$container->make("Perform");
全部コンテナがやってくれる
ytake
interfaceじゃなきゃだめなのか?
• コンテナが解決してくれるものなら何でも
• コンストラクタに文字列だったり配列だったり、なんでも良い
• それぞれのライブラリはそこら辺を上手くカバーしてくれます
• 所謂コンストラクタインジェクション
No!“
ytake
フィールドインジェクションって なんだ?
ytake
public class FrogMan { @Inject private Vehicle vehicle; } !
ytake
フィールドインジェクション
• プロパティに注入 • アノテーション(JSR-330 etc)
• 単純で分かり易いが、状況によってはテストし辛くなるのであまりお勧めされない
• PHPでもDIライブラリで実装してるものも結構ある
• javaは標準で使える (GuiceとかSpringFrameworkのとかあるけど)
java etc..“
ytake
Compiler!
ytake
PHPにはそんなものは無い (インタープリタ型)
ytake
そこまでして使いたいのか?
ytake
javaに寄せたライブラリは多い だがSpringに寄せたものはあまりない とりあえずやってみよう! PHPのコンテナ、アノテーションライブラリを使おう!
ytake
フィールドインジェクションをどう再現するか
• doctrine/annotation • リフレクション • コンパイラがないので作る
(nick/PHP-Parser) • Laravelユーザーなので
illuminate/container (利用者が少ないものを選んだ)
• Spring Framework! • オートスキャン @Componentだ
考えた“
ytake
illuminate/Container
• DIとしての機能はある • もちろんサービスロケーターも • バインディングのbindに慣れている
• 5のコンテナで@Qualifierに近い事が
• @Scopeの実装が楽
簡単“
ytake
Laravelコンテナはこういう感じ
ytake
$this->bind("hoge", "Hoge\Container\Repository");
hogeって名前を呼んだらHoge\Container\Repository くれ
binding1
ytake
$this->bind("AcmeInterface", "Acme");
このインターフェースが コンストラクタにあったらこのクラスを注入せよ
binding2
ytake
AppClassにはこれを注入せよ*次期バージョンから(develop only)
binding3
$container->when(‘AppClass) ->needs(‘HogeInterface) ->give(‘Hoge);
ytake
依存を解決して インスタンスを生成せよ! シングルトンもあり
newInstance
$container->make(‘AppClass);
ytake
@Component
• SpringのBeanと同じ様に
• Symfony/Finder 優秀
• andrewsville/php-token-reflectiontokenizerとリフレクションを使ったライブラリ
• ClassのみでComponent(“name”)
• インターフェイス, クラスの関連
コンテナに登録“
ytake
@Autowired
class Perform{ /** * @Autowired("Interface") */ protected $repository; }
ytake
だがしかし、 そもそも フィールドインジェクションの 仕組みは無い
ytake
コンストラクタに突っ込めば やりたい事が解決できる コンパイラとして継承したクラスを 吐き出して実行すれば良い
ytake
final class \CompiledPerform extends \Perform{ public function __construct( \Interface $repository ){ $this->repository = $repository; }}
ytake
こんな感じで継承クラスを 実行させる様にした
ytake
速度が遅い!
• 元のライブラリの10倍くらい遅い
• コンパイルしたクラスを吐き出して移行はそれを使う様にする(3倍遅いくらい)
• xhprofで見たらdoctrine/annotationが一番ボトルネックだった (キャッシュ忘れてた)
• フィールドインジェクションを毎回読むのも遅いので、 全部吐き出す様にした
キャッシュ“
ytake
結果
object(CompiledPerform)#20 (1) { ["repository":protected]=> object(Repository)#21 (0) { } }
できた
ytake
ボトルネックがautoloaderになった
ytake
待てよコンストラクタに突っ込むなら 要らないんじゃ・・・??
ytake
無駄な産物が出来てしまった・・ https://github.com/ytake/Iono.Container
ytake
ytake
ご清聴ありがとうございました