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.

Dependency Injection for Wordpress

9,127 views

Published on

Published in: Technology
  • Be the first to comment

Dependency Injection for Wordpress

  1. 1. Dependency Injection for WordPress Plugin Development Mike Toppa WordCamp Nashville April 21, 2012 #wcn12www.toppa.com @mtoppa
  2. 2. Mike Toppa● Director of Development, WebDevStudios● 17 years of experience in web development, project management, and team management● Universities: Georgetown, Stanford, Penn● Dot coms: E*Trade, Ask Jeeves● Start-ups: Finexa, Kais Candy Co● WordPress development for non-profitswww.toppa.com @mtoppa
  3. 3. Code is Poetrywww.toppa.com @mtoppa
  4. 4. We want code to be...● Easy to understand● Easy to change● Reusable (DRY)● Bug freewww.toppa.com @mtoppa
  5. 5. So why is it usually like this?“O.P.C” http://abstrusegoose.com/432
  6. 6. It happens because we are always in a hurry, and requirements are always changing.www.toppa.com @mtoppa
  7. 7. But coding fast and dirty only makes us slower in the long run.www.toppa.com @mtoppa
  8. 8. “We like to think we spend our time power typing, but we actually spend most of our time staring into the abyss.” - Douglas Crockford principal discoverer of JSON, Creator of JSLintwww.toppa.com @mtoppa
  9. 9. The ratio of time spent reading code versus writing is well over 10 to 1. Therefore, making code easy to read makes it easier to write. - Bob Martin Paraphrased from his book Clean Codewww.toppa.com @mtoppa
  10. 10. Clean code saves time, saves $$www.toppa.com @mtoppa
  11. 11. Clean code techniques● Using meaningful names● Dont repeat yourself (DRY)● Object oriented principles and patterns● Unit testing, test driven development (TDD)● The “boy scout rule”● Vertical slicing● ...and many morewww.toppa.com @mtoppa
  12. 12. Clean code techniques● Using meaningful names● Dont repeat yourself (DRY)● Object oriented principles and patterns● Unit testing, test driven development (TDD)● The “boy scout rule”● Vertical slicing● ...and many morewww.toppa.com @mtoppa
  13. 13. The SOLID Principles● Single Responsibility (SRP)● Open-Closed (OCP)● Liskov Substitution (LSP)● Interface Segregation (ISP)● Dependency Inversion (DIP)www.toppa.com @mtoppa
  14. 14. The SOLID Principles● Single Responsibility (SRP)● Open-Closed (OCP)● Liskov Substitution (LSP)● Interface Segregation (ISP)● Dependency Inversion (DIP)www.toppa.com @mtoppa
  15. 15. Shashin My plugin for displaying albums, photos, and videos from Picasa, Twitpic, and YouTube (and others coming soon)www.toppa.com @mtoppa
  16. 16. I used the new version as a test case for applying clean code principles to WordPress pluginswww.toppa.com @mtoppa
  17. 17. From LosTechies.com
  18. 18. My Shashin plugin consists of 44 classes, each of which has a meaningful name, follows the SRP, and “does one thing” PicasaPhotoDisplayer SettingsMenu YouTubeSynchronizer Uninstall etc.www.toppa.com @mtoppa
  19. 19. Shashin exampleclass Admin_ShashinInstall { // ... public function run() { $this->createAlbumTable(); $this->verifyAlbumTable(); $this->createPhotoTable(); $this->verifyPhotoTable(); $this->updateSettings(); return true; } // ...}www.toppa.com @mtoppa
  20. 20. Class Autoloading● The problem: ● PHP lacks an equivalent statement to “import” or “use” for classes ● Having to hardcode a bunch of file paths is extra work, and makes code harder to change● The solution: ● PHP 5.1.2 and spl_autoload_register() ● PHP Standards Working Group: PSR-0www.toppa.com @mtoppa
  21. 21. PSR-0: Official Description● Each "_" character in the CLASS NAME is converted to a DIRECTORY_SEPARATOR● The fully-qualified namespace and class is suffixed with ".php" when loading from the file system● Alphabetic characters... may be of any combination of lower case and upper case● ...And other rules about namespaces● Source: https://github.com/php-fig/fig- standards/blob/master/accepted/PSR-0.mdwww.toppa.com @mtoppa
  22. 22. PSR-0 Example Admin_ShashinInstall is translated to Admin/ShashinInstall.phpwww.toppa.com @mtoppa
  23. 23. Toppa Plugin Libraries Autoloader// this is at the top of the main file for my Shashin pluginrequire_once dirname(__FILE__) . /../toppa-plugin-libraries-for-wordpress/ToppaAutoLoaderWp.php;$shashinAutoLoader = new ToppaAutoLoaderWp(/shashin);// thats it! I can now call “new” on any class under the shashin folder// and its class file will be automatically loadedwww.toppa.com @mtoppa
  24. 24. Shashins capabilities are shaped by how its objects are wired together, through implementation of the Dependency Inversion Principlewww.toppa.com @mtoppa
  25. 25. From LosTechies.com
  26. 26. Naïve model of a button and lamp Lamp Button + turnOn() + poll() + turnOff()class Button { private $lamp; public function __construct(Lamp $lamp) { $this->lamp = $lamp; } public function poll() { if (/* some condition */) { $this->lamp->turnOn(); } }} Example from “Agile Software Development”
  27. 27. Dependency inversion applied <<interface>> Button SwitchableDevice + poll() + turnOn() + turnOff() Lamp This is the Abstract Server pattern
  28. 28. class Lamp implements SwitchableDevice { public function turnOn() { // code } public function turnOff() { // code }}class Button { private $switchableDevice; public function __construct(SwitchableDevice $switchableDevice) { $this->switchableDevice = $switchableDevice; } public function poll() { if (/* some condition */) { $this->switchableDevice->turnOn(); } }}
  29. 29. A web of collaborating objects● The SRP and DIP together drive a “composition” approach to OO design● From Growing Object Oriented Software, Guided by Tests: "An object oriented system is a web of collaborating objects... The behavior of the system is an emergent property of the composition of the objects - the choice of objects and how they are connected... Thinking of a system in terms of its dynamic communication structure is a significant mental shift from the static classification that most of us learn when being introduced to objects."
  30. 30. Composition (“Has a...”) vs. Inheritance (“Is a...”)www.toppa.com @mtoppa
  31. 31. The SRP is about objects that do one thing The DIP is about how to wire them together to create working, flexible softwarewww.toppa.com @mtoppa
  32. 32. Never, ever do thisclass Button { private $lamp; public function __construct() { $this->lamp = new Lamp(); } //...}www.toppa.com @mtoppa
  33. 33. Instead, you want to inject the object dependency Dependency injection!www.toppa.com @mtoppa
  34. 34. Dependency injection is one of many design patterns for implementing the Dependency inversion principlewww.toppa.com @mtoppa
  35. 35. It comes in two flavorswww.toppa.com @mtoppa
  36. 36. Constructor injectionpublic function __construct(SwitchableDevice $switchableDevice) { $this->switchableDevice = $switchableDevice;}www.toppa.com @mtoppa
  37. 37. Setter injectionpublic function setSwitchableDevice(SwitchableDevice $switchableDevice) { $this->switchableDevice = $switchableDevice;}www.toppa.com @mtoppa
  38. 38. Which to use? It dependswww.toppa.com @mtoppa
  39. 39. Dependency chains If class A depends on class B, and class B depends on class C, class A should be blissfully unaware of class Cwww.toppa.com @mtoppa
  40. 40. To do this without going insane, you need an injection containerwww.toppa.com @mtoppa
  41. 41. Example from Shashinclass Lib_ShashinContainer { // … public function getPhotoRefData() { if (!isset($this->photoRefData)) { $this->photoRefData = new Lib_ShashinPhotoRefData(); } return $this->photoRefData; } public function getClonablePhoto() { if (!isset($this->clonablePhoto)) { $this->getPhotoRefData(); $this->clonablePhoto = new Lib_ShashinPhoto($this->photoRefData); } return $this->clonablePhoto; }www.toppa.com @mtoppa
  42. 42. Example continued public function getClonablePhotoCollection() { if (!isset($this->photoCollection)) { $this->getClonablePhoto(); $this->getSettings(); $this->clonablePhotoCollection = new Lib_ShashinPhotoCollection(); $this->clonablePhotoCollection->setClonableDataObject($this->clonablePhoto); $this->clonablePhotoCollection->setSettings($this->settings); } return $this->clonablePhotoCollection; }www.toppa.com @mtoppa
  43. 43. Beyond the textbook exampleswww.toppa.com @mtoppa
  44. 44. What to do when you need a new object inside a loop One solution is cloningwww.toppa.com @mtoppa
  45. 45. Shashin Exampleclass Admin_ShashinSynchronizerPicasa extends Admin_ShashinSynchronizer { // … public function syncAlbumPhotos(array $decodedAlbumData) { // … foreach ($decodedAlbumData[feed][entry] as $entry) { $photoData = $this->extractFieldsFromDecodedData($entry, $photoRefData,picasa); // ... $photo = clone $this->clonablePhoto; $photo->set($photoData); $photo->flush(); }www.toppa.com @mtoppa
  46. 46. What if you need a new object inside a loop, but cant know the subtype youll need ahead of time? Let the injection container figure it outwww.toppa.com @mtoppa
  47. 47. Shashin Exampleclass Public_ShashinLayoutManager { // ... public function setTableBody() { // … for ($i = 0; $i < count($this->collection); $i++) { // ... $dataObjectDisplayer = $this->container->getDataObjectDisplayer( $this->shortcode, $this->collection[$i] ); $this->tableBody .= $dataObjectDisplayer->run(); // ... }www.toppa.com @mtoppa
  48. 48. Dependency injection: key benefits● Makes your object dependencies adaptable to emerging needs● With an injection container, simplifies managing dependency chains● Supports “preferring polymorphism to conditionals”, making it easy to add new class subtypeswww.toppa.com @mtoppa
  49. 49. Will this proliferation of objects eat up all my memory? Nowww.toppa.com @mtoppa
  50. 50. Use dependency injection to instantiate only the objects you need, when you need themwww.toppa.com @mtoppa
  51. 51. Make immutable objects into properties of the container, so you only need to instantiate them oncewww.toppa.com @mtoppa
  52. 52. PHP 5 has improved memory management“In PHP 5, the infrastructure of the object model wasrewritten to work with object handles. Unless youexplicitly clone an object by using the clone keyword youwill never create behind the scene duplicates of yourobjects. In PHP 5, there is neither a need to pass objectsby reference nor assigning them by reference.”From http://devzone.zend.com/article/1714www.toppa.com @mtoppa
  53. 53. But dont overdo it:avoid needless complexity

×