Note that there are some explanatory texts on larger screens.

plurals
  1. PODependency Injection: pulling required components when they are actually needed
    primarykey
    data
    text
    <p>The gist behind DI is to relieve a class from creating and preparing objects it depends on and pushing them in. This sounds very reasonable, but sometimes a class does not need all the objects, that are being pushed into it to carry out its function. The reason behind this is an "early return" that happens upon invalid user input or an exception thrown by one of the required objects earlier or the unavailability of a certain value necessary to instantiate an object until a block of code runs.</p> <p>More practical examples:</p> <ul> <li>injecting a database connection object that will never be used, because the user data does not pass validation (provided that no triggers are used to validate this data)</li> <li>injecting excel-like objects (PHPExcel e.g.) that collect input (heavy to load and instantiate because a whole library is pulled in and never used, because validation throws an exception earlier than a write occurs)</li> <li>a variable value that is determined within a class, but not the injector at runtime; for instance, a routing component that determines the controller (or command) class and method that should be called based on user input</li> <li>although this might be a design problem, but a substantial service-class, that depends on a lot of components, but uses only like 1/3 of them per request (the reason, why i tend to use command classes instead of controllers)</li> </ul> <p>So, in a way pushing in all necessary components contradicts "lazy-loading" in the way that some components are created and never used, that being a bit unpractical and impacting performance. As far as PHP is concerned - more files are loaded, parsed and compiled. This is especially painful, if the objects being pushed in have their own dependencies.</p> <p>i see 3 ways around it, 2 of which don't sound very well:</p> <ul> <li>injecting a factory</li> <li>injecting the injector (an anti-pattern)</li> <li>injecting some external function, that gets called from within the class once a relevant point is reached (smtg like "retrieve a PHPExcel instance once data validation finished"); this is what i tend to use due to its flexibility</li> </ul> <p>The question is what's the best way of dealing with such situations / what do you guys use?</p> <p><strong>UPDATE</strong>: @GordonM here are the examples of 3 approaches:</p> <pre><code>//inject factory example interface IFactory{ function factory(); } class Bartender{ protected $_factory; public function __construct(IFactory $f){ $this-&gt;_factory = $f; } public function order($data){ //validating $data //... return or throw exception //validation passed, order must be saved $db = $this-&gt;_factory-&gt;factory(); //! factory instance * num necessary components $db-&gt;insert('orders', $data); //... } } /* inject provider example assuming that the provider prepares necessary objects (i.e. injects their dependencies as well) */ interface IProvider{ function get($uid); } class Router{ protected $_provider; public function __construct(IProvider $p){ $this-&gt;_provider = $p; } public function route($str){ //... match $str against routes to resolve class and method $inst = $this-&gt;_provider-&gt;get($class); //... } } //inject callback (old fashion way) class MyProvider{ protected $_db; public function getDb(){ $this-&gt;_db = $this-&gt;_db ? $this-&gt;_db : new mysqli(); return $this-&gt;_db; } } class Bartender{ protected $_db; public function __construct(array $callback){ $this-&gt;_db = $callback; } public function order($data){ //validating $data //... return or throw exception //validation passed, order must be saved $db = call_user_func_array($this-&gt;_db, array()); $db-&gt;insert('orders', $data); //... } } //the way it works under the hood: $provider = new MyProvider(); $db = array($provider, 'getDb'); new Bartender($db); //inject callback (the PHP 5.3 way) class Bartender{ protected $_db; public function __construct(Closure $callback){ $this-&gt;_db = $callback; } public function order($data){ //validating $data //... return or throw exception //validation passed, order must be saved $db = call_user_func_array($this-&gt;_db, array()); $db-&gt;insert('orders', $data); //... } } //the way it works under the hood: static $conn = null; $db = function() use ($conn){ $conn = $conn ? $conn : new mysqli(); return $conn; }; new Bartender($db); </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload