Note that there are some explanatory texts on larger screens.

plurals
  1. PODoes PHP 5.4 object dereferencing successfully mitigate the drawbacks of static storage parameter in this DI container?
    text
    copied!<p><strong>PUBLIC SERVICE UPDATE:</strong></p> <p>I've learned a lot since I originally posed this question. If you're reading this, please take my advice and avoid <code>static</code> altogether. Just. Don't. Use. It. <em>There is no way to dependency injection; dependency injection is the way.</em></p> <hr> <p>I've recently spent a lot of time digging into various Inversion of Control (<strong>IOC</strong>) concepts. I totally agree with those who believe a <strong>Service Locator</strong> is an anti-pattern. I built one to tinker with and was aghast at the power it allowed for importing "global" entities in the middle of classes using static locator methods as well as the possibility for hiding the actual dependencies of an object.</p> <p>Moving on from the service locator I set out to create a Dependency Injection (<strong>DI</strong>) container that gave me the flexibility of static dependency access without the concomitant drawbacks of static variables.</p> <p>Here's a simple example of such an implementation:</p> <pre><code>&lt;?php class Container { protected static $params = []; public function store($key, $val) { static::$params[$key] = $val; return $this; } public function fetch($key) { if (isset(static::$params[$key])) { return static::$params[$key]; } $msg = "No parameter match found in container: $key"; throw new OutOfBoundsException($msg); } } $container = new Container; $container-&gt;store('widgetDep', new WidgetDependency); $container-&gt;store('kumquatDep', new KumquatDependency); // and somewhere else in the application without access to the global namespace // (i.e. the $container instance we just created) ... $widget = new Widget(new Container); $kumquat = new Kumquat(new Container); </code></pre> <p>This seems a step in the right direction because the static <code>$params</code> property is protected and no static methods exist to access or manipulate it in a "global" static scope: an object requires access to the container to access dependencies.</p> <h2>Oh, wait ...</h2> <p>Unfortunately, storing dependencies in this container means that now every dependency-injected object has <strong>a faux-dependency on the container object, thus hiding its <em>real</em> dependencies.</strong> Another negative side-effect would be that every object would be given access to every available dependency in the container, and obviously, a <em>Widget</em> object shouldn't have access to a <em>Kumquat</em> object's dependencies. Also, using an abstract factory with this approach does nothing but move the fake dependency out of the <em>Widget</em> and <em>Kumquat</em> classes and into the factory.</p> <h2>A PHP 5.4 alternative</h2> <p>With 5.4's new object construction dereferencing capabilities, we could do something like the following without needing access to the already created <code>$container</code> instance that exists in the global namespace:</p> <pre><code>$widget = new Widget((new Container)-&gt;fetch('widgetDep')); $kumquat = new Kumquat((new Container)-&gt;fetch('kumquatDep')); </code></pre> <p>Using this approach we've successfully:</p> <ol> <li>Eliminated the container dependency from the Widget and Kumquat objects, allowing their constructors to typehint the specific dependency objects they require;</li> <li>Prevented the downstream Widget and Kumquat objects having access to dependencies they shouldn't know exist;</li> <li>Retained static dependency storage capabilities.</li> </ol> <p>Now, a possible drawback is that this approach means the developer must be disciplined enough to not pass a full <code>Container</code> object as a dependency. This is crucial.</p> <h2>So the question is ...</h2> <p>In two parts:</p> <ol> <li>What concrete drawbacks do you see with this approach, and</li> <li>Is the static <code>Container::$params</code> even necessary? Should it instead be a standard protected property accessed by top-of-the-object-graph factory classes/methods in the global namespace anyway (obviating the need for <code>static</code>)?</li> </ol>
 

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