Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Upcoming SlideShare
Symfony2 & l'architecture Rest
Next
Download to read offline and view in fullscreen.

Share

Dependency Injection Smells

Download to read offline

Presentation about dependency injection smells in PHP.

Related Books

Free with a 30 day trial from Scribd

See all

Dependency Injection Smells

  1. 1. Dependency Injection SmellsFeaturing Zend,Symfonyand DoctrinecodeMatthias Noback - PHP developer and consultantDutch PHP Conference - 6/7/2013
  2. 2. Matthias NobackDutch developerConsultancy, training, writingClean code···2/44
  3. 3. What is a dependency?A needs a B to do its jobthereforeB is a dependency of A3/44
  4. 4. Dependency managementTo make sure that A will have a B, A can:4/44
  5. 5. 1. Create a B5/44
  6. 6. 2. Fetch a B6/44
  7. 7. 3. Receive a B7/44
  8. 8. Dependency managementStrategy 1: Do it yourself8/44
  9. 9. Why not...Instantiate classes with the newoperator?classSomeClass{publicfunctiondoSomething(){$logger=newLogger();$logger->debug(Nothingtoseehere);}}PHP9/44
  10. 10. Why not...Instantiate variable classes?classSomeClass{publicfunction__construct($loggerClass){$this->loggerClass=$loggerClass;}publicfunctiondoSomething(){$logger=new{$this->loggerClass}();$logger->debug(Veryflexible,right?);}}PHP10/44
  11. 11. Why not...Instantiate in overridable methods?classSomeClass{publicfunctiondoSomething(){$logger=$this->createLogger();$logger->debug(Matthiaswashere);}protectedfunctioncreateLogger(){returnnewLogger();}}PHP11/44
  12. 12. Dependency managementStrategy 2: Fetch your dependencies12/44
  13. 13. Why not...Use a global/static variable?classSomeClass{publicfunctiondoSomething(){Logger::getInstance()->debug(Matthiaswashere);}}PHP13/44
  14. 14. Why not...Use a service container/manager/registry?classSomeClass{publicfunction__construct(ContainerInterface$container){$this->container=$container;}publicfunctiondoSomething(){$this->container->get(logger)->log(Wow,thatwasquiteadistance!)}}PHP14/44
  15. 15. Dependency managementStrategy 3: Be passive about your dependencies15/44
  16. 16. Injecting dependencies by their interfaceclassSomeClass{publicfunction__construct(LoggerInterface$logger){$this->logger=$logger;}publicfunctiondoSomething(){$this->logger->info(Ah,muchbetter);}}PHP16/44
  17. 17. Strategy review1. Create your own dependencies2. Fetch your dependencies17/44
  18. 18. Strategy reviewYou are in control of your dependencies18/44
  19. 19. Strategy review3. Have your dependencies injected19/44
  20. 20. Strategy reviewYou are not in control of your dependenciesSomeone elseThis is called "inversion of control" (IoC)···20/44
  21. 21. Dependency injectionDependency injection is a ,used to21/44
  22. 22. Code reviewZendCrypt
  23. 23. Code reviewZendCryptclassBlockCipher{publicfunction__construct(SymmetricInterface$cipher){$this->cipher=$cipher;}publicfunctionencrypt($data){...}publicfunctiondecrypt($data){...}}PHP23/44
  24. 24. ZendCryptDependency Injection Smell: Static dependencyStatic dependencies are hard-to-control dependenciesclassBlockCipher{publicstaticfunctionfactory($adapter,$options=array()){$plugins=static::getSymmetricPluginManager();$adapter=$plugins->get($adapter,(array)$options);returnnewstatic($adapter);}}PHP24/44
  25. 25. ZendCryptDependency Injection Smell: Missing dependency auto-recoveryIf you have a dependency, act like you are .publicstaticfunctiongetSymmetricPluginManager(){if(static::$symmetricPlugins===null){static::setSymmetricPluginManager(newSymmetricPluginManager());}returnstatic::$symmetricPlugins;}PHP25/44
  26. 26. ZendCryptDependency Injection Smell: Hidden dependenciesIf you have a dependency, make it explicit.classSymmetricPluginManagerextendsAbstractPluginManager{protected$invokableClasses=array(mcrypt=>ZendCryptSymmetricMcrypt,);}PHP26/44
  27. 27. ZendCryptSuggested refactoringuseZendCryptSymmetricMcrypt;useZendCryptSymmetricBlockCipher;$cipher=newMcrypt(array(algo=>aes));$blockCipher=newBlockCipher($cipher);PHPNo SymmetricPluginManagerNo factory()method··27/44
  28. 28. ZendCryptDependency Injection Smell: Creation logic reductionMake way for complex creation logic (and dont think the newoperator willsuffice).publicstaticfunctionsetSymmetricPluginManager($plugins){if(is_string($plugins)){$plugins=new$plugins();}if(!$pluginsinstanceofSymmetricPluginManager){thrownewExceptionInvalidArgumentException();}static::$symmetricPlugins=$plugins;}PHP28/44
  29. 29. Code reviewSymfonyBundleFrameworkBundle
  30. 30. SymfonyBundleFrameworkBundleHttpCacheabstractclassHttpCacheextendsBaseHttpCache{publicfunction__construct(HttpKernelInterface$kernel,$cacheDir=null){$this->kernel=$kernel;$this->cacheDir=$cacheDir;parent::__construct($kernel,$this->createStore(),$this->createEsi(),array_merge(array(debug=>$kernel->isDebug()),$this->getOptions()));}}PHP30/44
  31. 31. SymfonyBundleFrameworkBundleDependency Injection Smell: Factory methodsDont require developers to use inheritance for replacing dependencies.abstractclassHttpCacheextendsBaseHttpCache{protectedfunctioncreateEsi(){returnnewEsi();}protectedfunctioncreateStore(){returnnewStore($this->cacheDir?:$this->kernel->getCacheDir()./http_cache);}}PHP31/44
  32. 32. SymfonyBundleFrameworkBundleDependency Injection Smell: Programming against an implementationHttpCachehas a dependency on HttpKernelInterface...abstractclassHttpCacheextendsBaseHttpCache{publicfunction__construct(HttpKernelInterface$kernel,$cacheDir=null){...}}PHPinterfaceHttpKernelInterface{publicfunctionhandle(Request$request,$type=self::MASTER_REQUEST,$catch=true);}PHP32/44
  33. 33. SymfonyBundleFrameworkBundleDependency Injection Smell: Programming against an implementation... but it uses of the interface methodsarray(debug=>$kernel->isDebug()), PHPreturnnewStore($this->cacheDir?:$this->kernel->getCacheDir()./http_cache); PHP$this->getKernel()->boot(); PHP33/44
  34. 34. SymfonyBundleFrameworkBundleSuggested refactoringProgram against an interface (strictly)Or: program against an implementation (and type-hint accordingly)Or: expand the interface to contain the methods you need···34/44
  35. 35. Code reviewDoctrineDBAL
  36. 36. DoctrineDBALDependency Injection Smell: Dependencies prohibitedabstractclassType{publicstaticfunctionaddType($name,$className){self::$typesMap[$name]=$className;}publicstaticfunctiongetType($name){if(!isset(self::$typeObjects[$name])){self::$typeObjects[$name]=newself::$typesMap[$name]();}returnself::$typeObjects[$name];}}Type::getType(datetime)->convertToPHPValue(2013-06-08);PHP36/44
  37. 37. DoctrineDBALDependency Injection Smell: Dependencies prohibitedclassEncryptedStringTypeextendsType{publicfunction__construct(BlockCipher$blockCipher){$this->blockCipher=$blockCipher;}publicfunctionconvertToDatabaseValue($value){return$this->blockCipher->encrypt($value);}publicfunctionconvertToPHPValue($value){return$this->blockCipher->decrypt($value);}}PHP37/44
  38. 38. DoctrineDBALDependency Injection Smell: Dependencies prohibitedWe can not override Type::__construct()since it is final.Dont neglect other classes needs (even if your class has everything it needs)Type::addType(encrypted_string,EncryptedStringType); PHPabstractclassType{finalprivatefunction__construct(){}}PHP38/44
  39. 39. DoctrineDBALDependency Injection Smell: Dependencies prohibitedWork-around: static dependencyclassEncryptedStringType{publicstatic$blockCiper;}EncryptedStringType::$blockCipher=...;PHP39/44
  40. 40. DoctrineDBALRecommended refactoring1. Split the Typeclass into an AbstractTypeand a TypeRegistry.2. Set a type instance, instead of just a class.$blockCipher=...;//ha,weknowhowtomakeone!$typeRegistry=newTypeRegistry();$encryptedStringType=newEncryptedStringType($blockCipher);$typeRegistry->setType(encrypted_string,$encryptedStringType);PHP40/44
  41. 41. In conclusionGood API design
  42. 42. Dependency injection smellsStatic dependencyMissing dependency auto-recoveryHidden dependenciesCreation logic reductionFactory methodsProgramming against an implementationDependencies prohibited·······42/44
  43. 43. Keep in mind...Be clear and open about what your dependencies areRequire only a minimum amount of dependenciesDevelop with your users (other developers) in mind···43/44
  44. 44. Thank youPlease leave some feedback at joind.in/8447twitter @matthiasnobackwww php-and-symfony.matthiasnoback.nlgithub github.com/matthiasnobackleanpub leanpub.com/a-year-with-symfony
  • 0iron0

    Feb. 7, 2020
  • Gudimetla

    Feb. 23, 2018
  • BoWenLi35

    Jul. 5, 2017
  • denisristic1

    May. 2, 2017
  • ExuperOkouya

    Dec. 11, 2015
  • mythii

    Sep. 25, 2015
  • theexperiences

    Mar. 9, 2015
  • Rios1984

    Feb. 10, 2014
  • jchr86

    Sep. 2, 2013
  • jmolivas

    Jun. 7, 2013

Presentation about dependency injection smells in PHP.

Views

Total views

9,138

On Slideshare

0

From embeds

0

Number of embeds

3,912

Actions

Downloads

60

Shares

0

Comments

0

Likes

10

×