PHP フィールドインジェクションに挑戦する PHP勉強会2014

Preview:

Citation preview

‹#›

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

ご清聴ありがとうございました