Tony Marston's Blog About software development, PHP and OOP

Dependency Injection for Heretics

Posted on 20th March 2026 by Tony Marston
Introduction
What is Dependency Injection (DI)?
Confusion between DI and Inversion of Control (IoC)
Other points of confusion
Criticisms by so-called "experts"
My heretical implementation
My version of a Client
An orthodox version of a DI Container
My version of a DI Container
Advantages of my heretical implementation
References
Comments

Introduction

I have often been lambasted by my critics for not following "best practices", but what they are actually saying is that I don't follow the same interpretation of best practices as they do. They look at my code and the only thing that they notice is that it looks different from theirs, and they cannot understand why it is different. If I am following the same rules as them then surely my code should look the same as theirs. They cannot see that the results which I achieve (more reusability, which means less code that I have to write) are better than theirs, they cannot see past the fact that they cannot recognise how I achieve those results. It is the fact that I choose follow a different path that my critics, whom I often call the "paradigm police", refer to me as a non-conformist, a heretic, a pariah and an outcast. To them I am a blight on the Object Oriented landscape.

First I will provide a small diagram of the structure used in the RADICORE framework:

Figure 1 - MVC plus 3 Tier Architecture

Model View controller DAO Presentation layer Business layer Data Access layer model-view-controller-03a (5K)

Each of the components in the above diagram is a hyperlink which will take you to a detailed explanation.

Following the Evans Classification these components have the following types:

When my critics started telling me You're not injecting your dependencies I had to do a google search to find out what is was and how to do it. I looked at the code samples and I could see straight away that there was nothing like that in my code. As my code already worked I could see no benefit in changing it to match those samples, so I decided to ignore them. The only thing it prompted me to do was to write Dependency Injection is EVIL. While writing this I suddenly realised that in my code I actually do use dependency injection but in a totally novel way. It was so novel that none of my critics spotted it, which just shows you how bright they are. As you will read below, in my implementation I do not inject objects into the client program, I inject class names which the client program can then instantiate into objects. I have never seen anybody else refer to such a mechanism, which just means that everybody else is just following the herd while mavericks or heretics like me are thinking outside the box.

In the RADICORE framework I use Dependency Injection in the following places:

I do NOT use Dependency Injection to perform any of the following:


What is Dependency Injection (DI)?

I never knew that the idea of dependency injection existed as a programming principle until one of my critics (of whom there are many) posed the question: I see no evidence of dependency injection anywhere in your code. How do you handle your dependencies? I replied that if any of my Model classes needs to communicate with another object then I either use the new keyword or call my singleton class. I was told that this was completely wrong. I was told that "proper" OO programmers use DI for every dependency without any exceptions.

In order to find out what this thing called "dependency injection" was and if it was worth my while to implement it I searched the interweb thingy for a proper definition and some examples of how it could/should be implemented. This is when I came across the The Dependency Inversion Principle which was written by Robert C. Martin (Uncle Bob) in 1996. I read the words and studied the example given in the "Copy" program and made the following observations:

This is the reason why I do not use any form of dependency injection if there is only a single object that can be used as a dependency.

I also noticed that, according to the Evans Classification, the COPY program is a service while each of the device objects is an entity. I also surmised that while it would be logical to inject an entity into a service it would not be logical to inject an entity into an entity or a service into an entity. This thought was reinforced when I came across the following:

As the COPY program was not a useful example when it came to building web pages in PHP I searched the interweb thingy again for examples from all those OO "experts" who supposedly exist in cyberspace. I was not impressed with what I found. None of the sample code I came across looked as if it could be fitted into my framework without major surgery. All I could see was my simple code which worked being replaced with complex code which achieved the same result but in a more roundabout and convoluted way, and I was not impressed. As I investigated further I became even more unimpressed and then a little confused.


Confusion between Dependency Injection (DI) and Inversion of Control (IoC)

While Dependency Injection is clearly demonstrated in the example COPY program which was provided in Robert C. Martin's original article called the The Dependency Inversion Principle I later came across this wikipedia article which had the same title but talked about something completely different. On top of this they took Robert C. Martin's original idea and re-named it to Dependency Injection. We now end up with the following completely different and unrelated principles:

  1. Dependency Injection (DI) - wikipedia
    Dependency Injection is a programming technique in which an object or function receives other objects or functions that it requires, as opposed to creating them internally. Dependency injection aims to separate the concerns of constructing objects and using them, leading to loosely coupled programs. The pattern ensures that an object or function that wants to use a given service should not have to know how to construct those services. Instead, the receiving "client" (object or function) is provided with its dependencies by external code (an "injector"), of which it is not aware.

    This matches the example COPY program. There are several ways in which a client can receive injected services:

    While the RADICORE framework does contain code which injects dependencies (Models) into a client (Controller), it has a particular implementation which I have not seen documented anywhere else. That implementation is the subject of this article.

  2. Inversion of Control (IoC) - wikipedia
    Inversion of Control is a design principle in which custom-written portions of a computer program receives the flow of control from an external source (e.g. a framework). In procedural programming, a program's custom code calls reusable libraries to take care of generic tasks, but with inversion of control, it is the external code or framework that is in control and calls the custom code.

    This is also known as the Hollywood Principle (don't call us, we'll call you) which is implemented using the Template Method Pattern. This uses an abstract superclass which contains a mixture of invariant/fixed methods which define the skeleton of an operation in terms of a number of steps. These fixed methods are interspersed with a number of variable/customisable methods which can be overridden in any concrete subclass in order to provide custom processing within that subclass.

    In the RADICORE framework there is an abstract table class which is inherited by every concrete table class. This abstract class provides all the boilerplate code, which includes primary validation, to handle the communication between the front-end Presentation layer and the back-end Data Access layer. Each concrete subclass may contain their own implementations for any of the customisable "hook" methods in order to process the business rules which are specific to that subclass. Every method called by a Controller on a Model, or a View on a Model, is a template method.

  3. Dependency Inversion Principle (DIP) - wikipedia
    Dependency Inversion Principle is a specific methodology for loosely coupled software modules. When following this principle, the conventional dependency relationships established from high-level, policy-setting modules to low-level, dependency modules are reversed, thus rendering high-level modules independent of the low-level module implementation details.
    The principle states:
    • High-level modules should not import anything from low-level modules. Both should depend on abstractions (e.g., interfaces).
    • Abstractions should not depend on details. Details (concrete implementations) should depend on abstractions.

    Try as I might I simply do not understand what this principle is trying to achieve or how it is supposed to work. It appears to say that if a client is dependent on another object then it is not supposed to call a method directly on that object, instead it calls an intermediate object interface (which does not contain an implementation) and somehow the interface transfers the call to an object which does contain an implementation. This does not compute. It is simply not possible to call a method without specifying an object which contains that method. I created my framework in PHP 4 which did not support interfaces, so I know for a fact that I do not need to go through an interface before I call a method.

    The description of this principle talks about Policy layers, Mechanism layers and Utility layers which do not exist in either the 3-Tier Architecture or the Model-View-Controller design pattern which form the backbone of my framework (as shown in Figure 1 above). Its implementation of the Model-View-Controller looks nothing like mine, and it refers to a host of other related patterns which do not appear in my framework. It is supposed to be based on Robert C. Martin's original idea, but to me it looks like someone has thrown a bucket of clever-sounding but unrelated words into the mix and created something which is as useful as a chocolate teapot.

    I find that putting the two words "dependency" and "inversion" in the same sentence to be completely confusing as they are completely separate principles. Here is an example of a misleading statement which I found in A quick intro to Dependency Injection: what it is, and when to use it from freecodecamp.org:

    Inversion of control - the concept behind DI
    This states that a class should not configure its dependencies statically but should be configured by some other class from outside.

    This makes no mention of polymorphism nor the swapping of dependent objects. Inversion of Control is having a framework that calls the code you write instead of you having to write code to call functions in a library while Dependency Injection is about swapping objects at runtime. One of these relies on multiple subclasses inheriting from the same abstract class to provide polymorphism, while the other relies on the abstract class to implement the Hollywood Principle via the Template Method Pattern. All this is achieved without any object interfaces.

    I already have a framework which works, and I do not see how this principle could possibly make it work better. I do not know how to write the code which follows this principle, so I am not going to waste my time trying.


Other points of confusion

In my investigation into the ways in which dependencies can be handled I came across various statements which show a lack of comprehension on the part of the author of those statements, such as the following:

1. Dependency injection aims to separate the concerns of constructing objects and using them

Rubbish. There are several things wrong with that statement:

2. DI leads to loosely coupled programs.

You have this backwards. DI does not lead to loosely coupled programs, it follows as a result of having loosely coupled programs. As described above in Robert C. Martin's example of a COPY program, DI provides the ability to select the dependent object at run time. This means that you must have a choice of several objects which share the same method signature. This is a result of polymorphism which allows different objects to be plug-compatible. This situation can only exist if your modules have loose coupling. Modules which have tight coupling are not interchangeable and therefore cannot be swapped at run time. To summarise:

3. The pattern ensures that an object or function that wants to use a given service should not have to know how to construct those services.

Surely a class can be instantiated into an object using nothing more than the new keyword. In the RADICORE framework I do not have to supply instructions on how any object should be configured as all my Models have only one configuration, and that is taken care of in the class constructor. This means that the user of a service does not need to know how to construct that service as that is hidden inside the service's constructor.

4. The receiving "client" (object or function) is provided with its dependencies by external code (an "injector").

There is no rule which says that the dependent object must be instantiated before it is injected. This is just a limitation built in to the early compiled languages. With PHP it is possible to inject the identity of the dependent class which can then be instantiated into an object within the receiving client.

Criticisms by so-called "experts"

In February 2015 there was a sitepoint thread titled Dependency Injection: a discussion of the pros and cons which discussed an article which I wrote in 2011 called Dependency Injection is Evil. Some of the statements made in that thread caused to to update that article with Criticisms by so-called "experts". Some of those statements are repeated below:

1. There are no circumstances in which DI is inappropriate.

This just proves that the "expert" did not understand the circumstances in which DI *IS* appropriate, which are:

This is precisely why I only inject entities into services. I have hundreds of alternative entities (table classes) in my application, but only one version for each of my services.

2. You are claiming that an alternative to DI is to use a singleton

When I do not wish to use DI to split the instantiation of an object from a call on one of its methods I execute those two steps, which by the way require no more than a single line of code each, using code as simple as the following:

$object = singleton::getInstance('foobar');
$result = $object->method($arg);

Here is another version which is much longer:

require 'classes/foobar.class.inc';
$dbobject = new foobar();
$result = $object->method($arg);

This "expert" then claimed that I was saying that using a singleton (which is NOT evil by the way) was an alternative to using DI. I claimed no such thing. What I actually said was that an alternative to using DI was NOT to use DI, which can be achieved with or without the use of a singleton. Note also that I do not use the factory method pattern as every one of my objects has a single configuration which is loaded in class constructor. The idea of putting that code in another method and then having additional code to call that method strikes me as being a complete waste of key strokes.

3. You are arguing that DI doesn't have any benefits.

This expert is mis-quoting me again. DI has benefits when it is used in appropriate circumstances (i.e. when there is a choice of multiple objects which can be used as a dependency), but it has zero benefits, and also violates YAGNI, when it is used in inappropriate circumstances (i.e. when there is only a single object which can be used as a dependency). It is plain to me that this numpty does not have the brain capacity to understand what "when appropriate" means.


My heretical implementation

When I created my PHP framework, which is actually a rewrite of a framework which I wrote first in COBOL and then in UNIFACE, I had no knowledge of the SOLID, GRASP or any other OO principles or design philosophies. Instead I just read the PHP manual, along with a few of the online resources which were available at that time, and played it by ear, making it up as I went along. The manual explained the mechanics of encapsulation and inheritance, but sadly it did not mention polymorphism or how to use it. For this I had to take a stab in the dark.

I had noticed that the primary difference between procedural and object oriented programming was that a procedural function could only be defined once, meaning that it was not allowed to have more than one function with the same name. However, if a function is defined within a class, in which case is is called a "method", it is allowed to have a function (method) with the same name in any number of other classes. I had already read that the purpose of OOP was to take advantage of Encapsulation, Inheritance and Polymorphism to increase code reuse and decrease code maintenance, so I assumed that the ability to access multiple objects using a common set of method names could be useful.

When I started to write my own PHP code I began with a Sample Application as a proof of concept. There were two design decisions I made from the outset based on what I had learned with the writing of database applications in other languages in the previous 20 years:

  1. It had to be based on the 3-Tier Architecture which I first encountered when working with UNIFACE. This was surprisingly easy to implement in PHP as object oriented programming is 2-tier by default. After you have built a class which represents the Model of an entity, something which encapsulates both the data for that entity and the operations which can be performed on that data, you will need an additional object (which I later referred to as a Controller) which instantiates that Model and then controls which methods are called on that Model to perform certain operations.
  2. Instead of constructing HTML documents by spitting out code fragments during the processing of a PHP script I decided to use a templating engine. This was because I had already noticed that there were lots of similarities in the screens when performing identical operations on different database tables, so I wanted to build those similarities into reusable templates. I had already encountered XML and XSL during my time with UNIFACE, as I had I already discovered how easy it was in PHP to use XSL Transformations I decided to stick with that technology. That was a decision that I have never regretted as, after a little refactoring, I was able to create a small set of Reusable XSL Stylesheets from which I could create any number of different HTML documents.

My first step was to create a Model class for a database table. As I already knew that every table needed to support the same CRUD operations I create a separate method for each. I did not follow the practice I saw in some of other people's code samples of having separate functions for load(), validate() and store() as I had already learned put such groups into wrapper functions such as insert(), read(), update() and delete(). I started by copying some code which I found in a book so that I could experiment with it.

<?php
require 'screens/person.detail.screen.inc';    // This identifies the XSL stylesheet
require 'classes/person.class.inc';            // This identifies the Model class
$dbobject = new Person(); 
$dbobject->setUserID    ( $_POST['userID']   ); 
$dbobject->setEmail     ( $_POST['email']    ); 
$dbobject->setFirstname ( $_POST['firstname']); 
$dbobject->setLastname  ( $_POST['lastname'] ); 
$dbobject->setAddress1  ( $_POST['address1'] ); 
$dbobject->setAddress2  ( $_POST['address2'] ); 
$dbobject->setCity      ( $_POST['city']     ); 
$dbobject->setProvince  ( $_POST['province'] ); 
$dbobject->setCountry   ( $_POST['country']  ); 

if ($dbobject->insertPerson($db) !== true) { 
    // do error handling 
} 
?> 

An alternative to this would be to pass each column as a separate argument on the method call like in the following:

$result = $dbobject->insertPerson($_POST['userID'],
                                  $_POST['email'],
                                  $_POST['firstname'],
                                  $_POST['lastname'],
                                  $_POST['address1'],
                                  $_POST['address2'],
                                  $_POST['city'],
                                  $_POST['province'],
                                  $_POST['country'],
                                  );

I did not like any of this code for the following reasons:

These have the effect of making each Controller tightly coupled to a particular Model, and as every competent programmer knows tight coupling is the enemy of polymorphism and therefore the enemy of reusability. After a little experimentation I changed it from being tightly coupled to loosely coupled as shown in My version of a Client.


My version of a Client

Here is my version of a client module (in this example it is a Controller), one that has dependencies.

<?php  // page controller script for the ADD1 pattern
require 'classes/$table_id.class.inc';
require 'screens/$screen.screen.inc';
$dbobject = new $table_id;
$result = $dbobject->insertRecord($_POST);
if ($dbobject->errors) {
    // do error handling 
}
?> 

The simple nature of this code relies on the fact that every Model subclass inherits the same set of methods from the abstract superclass, therefore the methods which are called can function on any Model class.

Each Controller can operate on any table class. There is a central library of 45 reusable Controllers, one for each of my Transaction Patterns. Each Controller has only a single View. For HTML output the screen structure file identifies which XSL Stylesheet is to be used and which data elements go where on the screen.


An orthodox version of a DI Container

The following code samples were copied from DI, DiC, & Service Locator Redux by Ralph Schindler:

A Service Locator, on the other hand, is better defined by a usage pattern, rather than the signature (pattern) of any particular class. This means that any object, upon being injected into a consuming object and then asked for an object, can be a service locator if it is capable of producing the requested object by a particular name or type. Effectively, a service locator can be a special container, or not; it can be a registry, or not; or it can be a factory, but perhaps not.

The only stipulation is that you've provided an object (the service locator) as a dependency to another object so that that the consuming object can then use the provided object (the service locator) to locate any dependencies. Instead of injecting n dependencies, you inject just one: the service locator. In code, it looks like this:
$container = new ContainerThatCanFindThings(); // implements LocatorInterface
$thing = new ThingThatHasDependencies($container);
The constructor for this ThingThatHasDependencies, might look like this
class ThingThatHasDependencies {
    public function __construct(LocatorInterface $container) {
        $this->dependencyOne = $container->get('DependencyOne');
        $this->dependencyTwo = $container->get('DependencyTwo');
    }
}
Now, you can see that any instance of ThingThatHasDependencies is now Container aware, which, depending on the context of the ThingThatHasDependencies, might be a good (or a bad) thing.

In the RADICORE framework the ThingThatHasDependencies is equivalent to a Controller or a View which are both dependent on one or more Models. Note that the $container has to be built before it can be injected into the CONTROLLER. The structure of the necessary components to support the orthodox implementation is shown below in Figure 2:

Figure 2 - Diagram of an orthodox DI Container

dependency-injection-for-heretics-01 (2K)

This functions as follows:


My version of a DI Container

Here is my version of a DI Container.

<?php  // component script
$table_id = "person";           // identify the Model
$screen   = 'person.detail';    // identify the View
require 'std.add1.inc';         // activate the Controller
?> 

Note the following:

Instead of having two pieces of code to first build the CONTAINER before passing it to the CONTROLLER I launch the CONTAINER (which is documented as a component script) directly from the URL. This means that my CONTAINER identifies all the dependencies as well as the component that will use those dependencies. This achieves the same result as the orthodox method, but with few and simpler components.

Figure 3 - Diagram of my heretical DI Container

dependency-injection-for-heretics-02 (1K)

This functions as follows:

Note the following:


Advantages of my heretical implementation

When other programmers look at my implementation of best practices the only thing that they seem to notice is that they are unfamiliar to them, that they are different. Because they do not understand how my code can be so different and still be "correct" they instantly assume that it must be "incorrect", that I am not following "best practices". They fail to realise that what I am actually doing is following a set of practices which produce the best results. The main motivation for object oriented programming is to create more reusable code as this leads to less maintenance. The best results can be measured by the volume of reusable code which manifests itself by the elimination of as much boilerplate code as possible, thus enabling the developer to spend more time on the important code, the business rules. If you read Write Only Business Logic: Eliminate Boilerplate you will see that, using my heretical interpretation of "best practices" I have eliminated 100% (yes, ONE HUNDRED PERCENT) of the boilerplate code. As far as I am aware there is no other framework that can achieve this level of reusability, so there is no other framework that can claim to be better.

As an example I shall refer to an ERP Application which was written entirely using the RADICORE framework:

If I had followed the orthodox implementation of "best practices" it would be comprised of the following:

What few programmers fail to spot in the above description are the places where the Single Responsibility Principle (SRP) is violated:

  1. Having a Controller which is responsible for more than one user transaction.
  2. Having a Model which is responsible for more than one database table.

The following components would have to be built by hand, which would take time to both design and then build:

Due to the absence of common method names and the abundance of unique property names each Controller or View would be tightly coupled to a single Model, thus eliminating any polymorphism and the possibility of sharing components via dependency injection.

My unorthodox and heretical approach promotes loose coupling and maximises the opportunities for polymorphism and therefore reuse by dependency injection. This is because of the following:

This means then that if I have 45 Controllers which can be reused with any of my 400 Model classes I therefore have 45 x 400 = 18,000 (YES, EIGHTEEN THOUSAND) opportunities for polymorphism and dependency injection.

You should notice that my implementation adheres to the Single Responsibility Principle (SRP) in the following ways:

  1. Each Controller is responsible for a single user transaction for any Model where the orthodox approach is multiple transactions for a single Model
  2. Each Model is responsible for a single database table instead of multiple tables.

If the purpose of object oriented programming is to increase reusability and thereby decrease maintenance then how much reusability can be achieved and how can it be measured? The answer is given in Write Only Business Logic: Eliminate Boilerplate where it states that the only code which has value to the paying customer is that which processes the business logic. Everything else, which has been called glue code or, more commonly, boilerplate code, should be regarded as a candidate for being replaced with reusable modules instead of being duplicated in multiple places. When you consider the fact that in the RADICORE framework every user transaction can be generated by pressing buttons on a screen without the need to write any code - no PHP, no HTML, no SQL - this means that 100% (yes, ONE HUNDRED PERCENT) of the boilerplate code is provided for the developer and does not have to be written by the developer. Any additional business logic which is required can be added into individual concrete table subclasses using the various "hook" methods which have been built into the abstract table class.

So, the answer is that it *IS* possible for a framework to provide ONE HUNDRED PERCENT of the boilerplate code. If your framework cannot match that then I would suggest that you need to look for a framework that was written by someone more competent.

Here endeth the lesson. Don't applaud, just throw money.


References


counter