Your SlideShare is downloading. ×
Dependency Inversion and Dependency Injection in PHP
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Dependency Inversion and Dependency Injection in PHP

5,078
views

Published on

Published in: Technology, Business

1 Comment
4 Likes
Statistics
Notes
  • I've created an atricle about dependency inversion and php: http://www.jacopobeschi.com/post/solid-design-principles-and-php-dependency-inversion
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total Views
5,078
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
44
Comments
1
Likes
4
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. Dependency Inversion andDependency Injection in PHP Michael Toppa University of Pennsylvania Perelman School of Medicine Information Services August 11, 2011
  • 2. Dependency injection is a design pattern for implementingdependency inversion
  • 3. Dependency inversion* is a design principle *AKA The Hollywood Principle: “Dont call us, well call you”
  • 4. The SOLID Principles● Single Responsibility (SRP)● Open-Closed (OCP)● Liskov Substitution (LSP)● Interface Segregation (ISP)● Dependency Inversion (DIP)
  • 5. The SRP is about objects that do one thingThe DIP is about how to wire them together to create working, flexible software
  • 6. Formal Definition of the DIP● High level modules should not depend on low- level modules. Both should depend on abstractions.● Abstractions should not depend on details. Details should depend on abstractions. This definition and the following example are from Bob Martins book “Agile Software Development”
  • 7. 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(); } }}
  • 8. This solution violates the DIP● Button depends directly on Lamp ● Changes to Lamp may require changes to Button● Button is not reusable ● It cant control, for example, a Motor● The high level abstraction is missing ● “the truths that do not vary when the details are changed” ● “To detect an on/off gesture from a user and relay that gesture to a target object”
  • 9. From LosTechies.com
  • 10. Dependency Inversion Applied <<interface>> Button SwitchableDevice + poll() + turnOn() + turnOff() Lamp This is the Abstract Server pattern
  • 11. 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(); } }}
  • 12. What it means● Neither Button nor Lamp “own” the interface● Buttons can now control any device that implements SwitchableDevice● Lamps and other SwitchableDevices can now be controlled by any object that accepts a SwitchableDevice
  • 13. Patterns that implement the DIP● Abstract Server● Constructor injection● Setter injection● Interface injection● Factory pattern● Adapter pattern● Service locator pattern● Contextualized lookup (push)
  • 14. Never do thisclass MySqlDb { public function __construct($username, $password, $host) { // .. snip .. } public function executeSql($sql) { // .. snip .. }}class BookReader { private $_db; public function __construct() { $this->_db = new MySqlDb(DB_USER, DB_PASS, DB_HOST); } public function getChapters() { return $this->_db->executeSql(SELECT name FROM chapter); }} Example from Crafty documentation http://phpcrafty.sourceforge.net/documentation.php
  • 15. In addition to other DIP violations,you cannot write unit tests for that code
  • 16. Constructor injection solutioninterface Db { public function executeSql($sql);}class MySqlDb implements Db { public function __construct($username, $password, $host) { // .. snip .. } public function executeSql($sql) { // .. snip .. }}class BookReader { private $_db; public function __construct(Db $db) { $this->_db = $db; } public function getChapters() { return $this->_db->executeSql(SELECT name FROM chapter); }}
  • 17. Setter injection solutionclass BookReader { private $_db; public function __construct() { } public function setDb(Db $db) { $this->_db = $db; } public function getChapters() { return $this->_db->executeSql(SELECT name FROM chapter); }}
  • 18. Which to use?● Constructor injection gives you a valid object, with all its dependencies, upon construction● But constructor injection becomes hard to read and use when there are more than a few objects to inject ● This is especially true when subclassing● More about this in an upcoming slide...
  • 19. If class A depends on class B, and class B depends on class C,class A should be blissfully unaware of class C
  • 20. This supports loose coupling andlets you do dependency injection “just in time”
  • 21. To do this without going insane,you need an injection container
  • 22. Example from Shashinclass Lib_ShashinContainer { // ... public function __construct($autoLoader) { $this->autoLoader = $autoLoader; } public function getDatabaseFacade() { if (!$this->dbFacade) { $this->dbFacade = new ToppaDatabaseFacadeWp($this->autoLoader); } return $this->dbFacade; } public function getClonablePhoto() { if (!$this->clonablePhoto) { $this->getDatabaseFacade(); $this->clonablePhoto = new Lib_ShashinPhoto($this->dbFacade); } return $this->clonablePhoto; I am making the objects properties of the } container, because they happen to be} immutable objects, so they are reusable
  • 23. Container Benefits● Loose coupling - objects dont have to worry about the dependencies of the objects they use● Facilitates portability - specific implementations or subtypes are centralized in the container● Dependencies are clearly articulated in one place● Simple design
  • 24. Constructor vs setter injection: my personal preference● Start with constructor injection● As your design evolves, switch to setter injection once there are more than 2 objects to inject● If you rely on an injection container, you dont have to worry about forgetting to call a required setter
  • 25. Injection containers for PHP● Its not hard to roll your own● There are also many available for PHP ● Bucket ● PicoContainer ● Crafty ● Pimple ● Symfony comes with one
  • 26. Beyond the textbook examples
  • 27. What to do when you needa new object inside a loop One solution is cloning
  • 28. Example from Shashinclass 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(); } // ... } // ...} https://github.com/toppa/Shashin/
  • 29. 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 out
  • 30. Example from Shashinclass Public_ShashinLayoutManager { // ... public function setTableBody() { // … for ($i = 0; $i < count($this->collection); $i++) { // ... $dataObjectDisplayer = $this->container->getDataObjectDisplayer( $this->shortcode, $this->collection[$i], $this->thumbnailCollection[$i] ); $this->tableBody .= $dataObjectDisplayer->run(); // ... } // ... getDataObjectDisplayer() uses the passed in } arguments to determine which subtype of // ... DataObjectDisplayer to return}
  • 31. What makes an injection containerdifferent from the factory pattern?
  • 32. Good question!● An injection container can be used to generate more than one class of objects ● A factory generates objects of a single class (or set of class subtypes)● An injection container consists of methods that create and return objects – its a simple design ● A full factory pattern implementation can be complex, and hard to test*● Theyre not mutually exclusive – you can use a container to create and inject a factory! See http://blog.astrumfutura.com/2009/03/the-case-for-dependency-injection-part-1/
  • 33. Will this proliferation of objects eat up all the server memory?● No ● “In PHP 5, the infrastructure of the object model was rewritten to work with object handles. Unless you explicitly clone an object by using the clone keyword you will never create behind the scene duplicates of your objects. In PHP 5, there is neither a need to pass objects by reference nor assigning them by reference.” ● From http://devzone.zend.com/article/1714
  • 34. A web of collaborating objects● Dependency injection is all about 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."

×