PHP Advent Calendar 2014ã®11æ¥ç®ã§ããæ¨æ¥ã¯æ®éãããªãã¢ããã³ã°ãã¬ã¼ã ã¯ã¼ã¯AspectMockããã¯ãã«éããã§ãããææ¥ã¯ @shin1x1 ããã§ãã
ããããããããã¡ãã
çµç·¯
AspectMockã«ç¶ãã¦æ¬æ¥ã¯AOPã§ããDIããããã
å»å¹´ã®PHP Advent Calendarã§ã¯Ray.Diã¨Ray.Aopããã¡ã¾ããã
cf. PHP ã§Ray.Diã¨Ray.Aopããã£ã¦ã¿ã http://c4se.hatenablog.com/entry/2013/12/20/015945
ãè±å±ããã§Webãµã¤ããä½ã£ã¦ãããã¡ã«DIã欲ãããªãPimpleã使ãã¦ãã¾ãããããã¤ãè¦ãannotationã§ãã
ãã£ã¨DIãããã¤ããããï¼Ïï¼ãã§ãã¢ã¬ããã©ãããï¼ï¼âãã¨ããµã®ã§Pimpleãæ¡å¼µãã¦èªä½ãã¾ããã
cf. PHPã§DI (ä¾åæ§ã®æ³¨å
¥) framworkãä½ãã®ã¯ããªãã§n人ç®ã§ãï¼ http://c4se.hatenablog.com/entry/2014/10/31/190156
ãããæ¡å¼µãã0.2.0ããªãªã¼ã¹ãã¾ããã
cf. ranyuen/di https://packagist.org/packages/ranyuen/di#0.2.0
ç¹å¾´
READMEã«æ¸ãã¦ãããã¨ããå°ãã¥ã¤æ¸ãã¦ããã¾ããä½ãREADMEã¨éã²ã以ä¸ã®codeã¯testãã¦ãããç®æ¸¬ã§æ¸ãã¦ãã¾ãã
ããã¾ããªç¹å¾´ã¯ä»¥ä¸ã®3ã¤ã§ãã
- Pimple 3ã¨100%äºæã§ããRanyuen\Di\Containerã¯Pimple\Containerãç¶æ¿ãã¦ãã¾ããPimple 3ã使ãã¦ããã°ã
use Pimple\Container;
ãuse Ranyuen\Di\Contaier;
ã«æ¸ãæã¸ãã ãã§ããPimple 2以ä¸ã使ãã¦ããã°ãPimple 3ã«ç§»è¡ããã®ã¨åãæç¶ããå¿ è¦ã«ãªãã¾ããã¾ãä»å¾Pimpleãæ´æ°ããå ´åã追é¨ããäºå®ã§ãã - Pimpleã¨åæ§ã«ãè¨å®ã¯ä¸è¦ã§ããè¨å®ãè¡ãªãµå ´åãYamlãXMLãPHPã®è¨å®ãæ¸ããã¨ãªãç¡ããç°¡åãªannotationãæ¸ãã ãã§ä¾åã解決ãã¾ãã
- è¨å®ãããã¨ç¡ãAOPãè¡ãªãµãã¨ãã§ãã¾ããè¨å®ãè¡ãªãµå ´åãç°¡åãªannotationãæ¸ãã ãã§ãã
Ranyuen/Diã¯doctrine/annotationsã«ä¾åãã¦ãã¾ããphpDocumentorå½¢å¼ã®@varã¢ããã¼ã·ã§ã³ã®åè¨è¼ãFQNã«å±éããçºã ãã«ä½¿ãã¦ãããRanyuen/Diã®ã¢ããã¼ã·ã§ã³ã¯è»½éãªæ¹æ³ã§å®è£ ãã¦ãã¾ãã
åèã«ãããã®ã¯ä»¥ä¸ã®éãã§ãã
cf. Pimple http://pimple.sensiolabs.org/
cf. Ray.Di & Ray.Aop https://code.google.com/p/rayphp/
cf. PHP-DI http://php-di.org/
cf. Go! AOP http://go.aopphp.com/
cf. Laravel http://laravel.com/
installæ¹æ³
Composerã使ã²ã¾ãã
composer require ranyuen/di *0.2
PHPã®5.4以é (5.4, 5.5, 5.6) ã¨ææ°ã®HHVM (3.4.0) ããµãã¼ããã¾ãã
GPL v3 æãã¯ãã以éã§ã©ã¤ã»ã³ã¹ãã¾ãã
DIã®ä½¿ç¨ä¾
DI (Dependency Injection) ãAOP (Aspect Oriented Programming) ãä½æ 使ãµã®ãã¯ä»ã®ææ¸ã«è²ãã¾ãããã®ãããªãã¨ãã§ãã¾ãã
Pimpleã¨äºæã§ãã®ã§ãåã使ã²æ¹ãã§ãã¾ãã
<?php require_once 'vendor/autoload.php'; use Ranyuen\Di\Container; class Momonga { public $id; public function __construct($id = '') { $this->id = $id; } } $c = new Container; // ã³ã³ããã«å¤ãå ¥ããåãåºãã¾ãã $c['id'] = 'Some ID'; var_dump('Some ID' === $c['id']); // ã³ã³ããããåãåºãããã¨ãã«ãã³ã³ããã®å¥ã®å¤ã使ã¸ã¾ããããã§ã²ã¨ã¤ã²ã¨ã¤ä¾åã解決ãã¾ãã // åãååã§ã³ã³ããããåãåºããå¤ã¯ãããã©ã«ãã§ã¯æ¯ååä¸ã®objectã§ãã $c['momonga'] = function ($c) { return new Momonga($c['id']); }; var_dump($c['momonga'] instanceof Momonga); var_dump($c['id'] === $c['momonga']->id); var_dump($c['momonga'] === $c['momonga']); // åãåºã度ã«æ°ãã«objectãä½ããã¨ãã§ãã¾ãã $c['factory'] = $c->factory(function ($c) { return new Momonga; }); var_dump($c['factory'] instanceof Momonga); var_dump($c['factory'] !== $c['factory']); // Closureãã³ã³ããã«æ ¼ç´ããã¨ãã«ãäºéã®Closureã«ããç°¡åã«æ¸ãã¾ãã $c['protect'] = $c->protect(function () { return new Momonga; }); var_dump($c['protect']() instanceof Momonga); // objectãçæãä¾åãæ³¨å ¥ããClosureèªä½ãåç §ã§ãã¾ãã $c['raw'] = function ($c) { return new Momonga($c['id']); }; $raw = $c->raw('raw'); var_dump($raw($c) instanceof Momonga); // ä¸åº¦æ ¼ç´ããæ³¨å ¥Closureãããã¨ããæ¡å¼µã§ãã¾ãã $c['base'] = function ($c) { return new Momonga; }; $c->extend('base', function ($base, $c) { $base->id = $c['id']; return $base; }); var_dump($c['base'] instanceof Momonga); var_dump($c['id'] === $c['base']->id); // åãæ³¨å ¥ãå¤ãã®ã¢ããªã±ã¼ã·ã§ã³ã§è¡ãªãµå ´åãæ³¨å ¥ãclassã«åãåºãã¾ãã class MomongaProvider implements Ranyuen\Di\ServiceProviderInterface { public function register(Container $c) { $c['register'] = function ($c) { return new Momonga; }; } } $c->register(new MomongaProvider); var_dump($c['register'] instanceof Momonga);
以ä¸ã¯Pimpleã®æ©è½ã§ãã以ä¸ã§ã¯requireã¨useãçç¥ãã¾ãã
å (interfaceåãFQN) ãæå®ãã¦ã³ã³ããã«å¤ãæ ¼ç´ãåãåºãã¾ãããã®æ©è½ã¯ä¸»ã«Ranyuen/Diã®å é¨ã§ä½¿ãã¦ãã¾ãã
<?php namespace Momonga; class Momonga { } $c = new Container; $c->bind('Momonga\Momonga', 'momonga', function ($c) { return new Momonga; }); var_dump($c->getByType('Momonga\Momonga') instanceof Momonga);
ãããããRanyuen/Diã®æ©è½ã§ããconstructorã®å¼æ°ã«èªåã§æ³¨å ¥ã§ãã¾ããtype hintãå¼æ°ã®ååããä¾åã解決ãã¾ããtype hintãã解決ããå ´åãPimpleã®ArrayAccesså½¢å¼ã§ã¯ãªããbindã¡ã½ããã使ãµå¿ è¦ãããã¾ã (ååãã解決ããå ´åã¯ArrayAccesså½¢å¼ã§å åã§ãã以ä¸åã)ã
<?php class Momonga { } class Yuraru { public function __construct($id, $momonga, Momonga $m, $another = null) { var_dump('Some ID' === $id); var_dump($momonga instanceof Momonga); var_dump($m instanceof Momonga); } } $c = new Container; $c['id'] = 'Some ID'; $c->bind('Momonga', 'momonga', function ($c) { return new Momonga; }); $yuraru = $c->newInstance('Yuraru'); // æ³¨å ¥ããªãå¼æ°ã¯èªç±ã«æå®ã§ãã¾ãã $yuraru = $c->newInstance('Yuraru', ['Another']); $yuraru = $c->newInstance('Yuraru', [ 'another' => 'Another', 'id' => 'Another ID', ]);
@Inject
ã¢ããã¼ã·ã§ã³ã使ãã¦ãpropertyã«æ³¨å
¥ãããã¨ãã§ãã¾ããconstructorã§ã¯phpDocumentorå½¢å¼ã®@paramã¯ç¡è¦ãtype hintã ããåç
§ãã¾ãããpropertyã§ã¯@var
ã¢ããã¼ã·ã§ã³ãtype hintã®ä»£ã¯ãã«ä½¿ã²ã¾ãã
<?php class Momonga { } class Yuraru { /** @Inject */ private $momonga; /** * @var Momonga * @Inject */ private $m; public function ok() { var_dump($this->momonga instanceof Momonga); var_dump($this->m instanceof Momonga); } } $c = new Container; $c->bind('Momonga', 'momonga', function ($c) { return new Momonga; }); $yuraru = $c->newInstance('Yuraru'); $yuraru = new Yuraru; $c->inject($yuraru);
@Injectã¢ããã¼ã·ã§ã³ã«ååãæ¸ããã³ã³ããã«ç»é²ããã®ã¨ã¯å¥ã®ååã§åãåºããã¨ãã§ãã¾ããåãæ©è½ã§ãã@Namedã¢ããã¼ã·ã§ã³ã¯èª¬æãçç¥ãã¾ãã
<?php class Yuraru { /** @Inject('m=momonga') */ private $m; /** * @Inject('m=momonga,momo=momonga') */ public function __construct($m, $momo) { var_dump('Some mOmonga' === $m); var_dump('Some mOmonga' === $momo); } public function ok() { var_dump('Some mOmonga' === $this->m); } } $c = new Container(['momonga' => 'Some mOmonga']); $yuraru = $c->newInstance('Yuraru');
å¤ãåãåºãé¨åã§ã®ãã£ãã·ã¥ã¯Pimpleã®æ©è½ã§è¡ãªã£ã¦ãã¾ããnewInstanceã¡ã½ããã¨injectã¡ã½ããã«ããDIã¯ãä¾åã°ã©ãããã£ãã·ã¥ãã¾ãããã£ãã·ã¥ã¯æ¬¡versionã§æ´ã«æ¹åãã¾ãã
ãããã®Ranyuen/Diã®æ©è½ã¯Pimpleã®æ©è½ã¨åæã«ä½¿ã¸ã¾ããfactoryã®ä¾ã示ãã¾ãã
<?php class Momonga { } class Yuraru { /** @Inject */ public $momonga; /** * @var Momonga * @Inject */ public $factory; } $c = new Container; $c['momonga'] = function ($c) { return new Momonga; }; $c->bind('Momonga', 'factory', $c->factory(function ($c) { return new Momonga; })); $yuraru1 = $c->newInstance('Yuraru'); $yuraru2 = $c->newInstance('Yuraru'); var_dump($yuraru1->momonga === $yuraru2->momonga); var_dump($yuraru1->factory !== $yuraru2->factory);
次ã®æ©è½ãFacadeã¨å¼ã¶ã®ã¯ãå称ãåºç¯å²ãããæ°ããã¾ãããLaravelã«å£ã¤ã¦Facadeã¨å¼ãã§ããã¾ããã³ã³ããããå¤ãåãåºãã¨ããã³ã³ããèªä½ãæå ã«æã£ã¦ããªãã¦ããstaticã¢ã¯ã»ã¹ã®è¨æ³ã§ã¡ã½ãããå¼ã³åºãã¾ãã
<?php class Momonga { public function m() { return 42; } } $c = new Container; $c['momonga'] = function ($c) { return new Momonga; }; $c->facade('Gardea', 'momonga'); var_dump(42 === Gardea::m());
AOPã®ä½¿ç¨ä¾
ç¶æ¿ã§ããå ¨ã¦ã®ã¡ã½ããã¸ã¤ã³ã¿ã¼ã»ããã§ãã¾ããã¤ã³ã¿ã¼ã»ãã対象ã®ã¡ã½ããã¯ãã¡ã½ããåãã¡ã½ããåã®æ£è¦è¡¨ç¾ã§æå®ã§ãã¾ãã
<?php class Momonga { public function eat($a = null, $b = null) { echo "eat\n"; } public function act() { echo "act\n"; } } $c = new Container; $c->wrap('Momonga', ['eat', 'act'], functon ($ivk, $args, $me) { list($a, $b) = $args; echo "Before eat or act\n"; $result = $ivk($a, $b); echo "After eat or act\n"; }); $c->wrap('Momonga', ['/t$/'], functon ($ivk, $args, $me) { list($a, $b) = $args; echo "Before end with t\n"; $result = $ivk($a, $b); echo "After end with t\n"; }); $momonga = $c->newInstance('Momonga'); $momonga->eat(); $momonga->act();
å é¨ã§ã¯ãã¿ã¼ã²ããã®classãç¶æ¿ããã¯ã©ã¹ãçæãã¾ããçæãããclassã¸ã¯ãã³ã³ãããéãã¦ããã¢ã¯ã»ã¹ã§ãã¾ããã
staticã¡ã½ãããç¶æ¿ãããã®ã§ãã¤ã³ã¿ã¼ã»ããã§ãã¾ããRubyãJavaScriptããæ¥ãã¨èª¤è§£ãã¾ãããPHPã®static修飾ã¯ãéçãã§ãã£ã¦ãã¯ã©ã¹ã¡ã½ããã§ã¯ããã¾ãããPHPã«ã¯ã©ã¹ã¡ã½ãããã¯ã©ã¹ããããã£ã¯ç¡ããéçã¡ã½ããã¨éçããããã£ã§ãã
<?php class Momonga { public static function eat() { } } $c = new Container; $c->wrap('Momonga', ['eat'], function ($ivk, $args, $me) { return $ivk(); }); $momonga = $c->newInstance('Momonga'); $momonga::eat();
@Wrap
ã¢ããã¼ã·ã§ã³ãæ¸ãèªåã§ã¤ã³ã¿ã¼ã»ããã§ãã¾ãã
<?php class Momonga { /** @Wrap('fruit,strange') */ public function eat() { } } $c = new Container; $c['strange'] = $c->propect(function ($ivk, $args, $me) { echo 'Strange '; return $ivk(); }); $c['fruit'] = $c->propect(function ($ivk, $args, $me) { echo "fruit\n"; return $ivk(); }); $c->newInstance('Momonga')->eat();
éçºæ¹æ³
CONTRIBUTINGãã覧ãã ããã
äºäºã§ããlocalã§ã¯æ´ã«,/test.sh
ã«ä»¥ä¸ã®ãã¡ã¤ã«ãç½®ãã¦å®è¡ãã¦ãã¾ãã
#!/bin/bash set -e phpenv local 5.6.1 phpunit phpenv local system phpunit phpenv local 5.6.1 hhvm vendor/bin/phpunit phpenv local 5.6.1
以ä¸ã§ãã次ã®ãªãªã¼ã¹ã¯0.2.1ã«ãªãã¾ãã