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 I actually do use dependency injection (DI) but in a totally novel way. It was so novel that none of my critics spotted it, which just shows you how observant they were. It became quite obvious to me that few programmers had ever gone to the source of this principle by reading The Dependency Inversion Principle which was written by Robert C. Martin (Uncle Bob) in 1996, and instead were regurgitating some secondhand interpretations of how it should be done without first identifying why it should be done. This led them to commit the following newbie mistakes:
read and write methods.From the above points I concluded that DI was designed as a means to take advantage of polymorphism, so that an object which calls polymorphic methods can, instead of being tightly coupled to a single named dependent object, be injected at run time with any object which supports those methods, thus changing it to loosely coupled. This makes the calling object reusable with any one of those dependents, and since a major motivation for object-oriented programming is software reuse, the larger the number of dependent objects which can be called from a single source the better.
As you will read below I found the document which written by the author of this principle, read what he wrote, and then worked out how to implement it within my code base to produce the maximum benefit (i.e. the maximum amount of reusable code) with the minimum of effort. Instead of following the herd and duplicating other people's implementations I created my own version, but because it was new and different they failed to spot that it achieved the objectives described by Uncle Bob without copying any existing implementation. Because they did not recognise my implementation they assumed that I was not using DI at all, and so they accused me of not being a "proper" OO programmer, not a follower of the true religion, which made me into a maverick and a heretic.
In the RADICORE framework I use Dependency Injection (DI) in the following places:
I do NOT use Dependency Injection to perform any of the following:
In my long career I have worked with many people with varying degrees of experience and ability. When trying to identify the differences between the adept and the inept, the organ grinders from the monkeys, the engineers from the oily rags, I have made the following observations:
There are two ways in which an idea can be implemented - indiscriminately or intelligently.
The indiscriminate use of an idea shows that the user does not have the ability to understand what the phrase when appropriate
means. They do not understand that implementing an idea in the wrong way or in the wrong place, such as inserting code to deal with a choice of dependent objects when there is no choice, is not only a waste of time (it actually violates the YAGNI principle), they are actually making the software less maintainable by causing a future maintainer to read code that is totally useless. This causes confusion instead of clarity.
Some people know only what they have been taught while others know what they have learned.
Those who follow what they have been taught without thinking on the assumption that their teacher was an expert and should never be contradicted or even questioned often do not realise that those teachings may be out of date, may have been based on wrong assumptions, or may have been created by users of compiled and statically typed languages which are no longer relevant in the modern world of interpreted and dynamically typed languages. How many of those programming principles which were created for the Smalltalk language in the 1970s are actually still valid in the 2020s, some 50 years later?
If programmers do not understand the purpose behind an idea, the problem it was designed to solve, then simply duplicating someone else's implementation may not yield the best results. This runs contrary to the notion of constructionist learning in which students start with a set of ideas and refine them through experimentation in which they build solutions to real-world problems. I created my prototype by taking what was taught by others and experimenting with it until I came up with something simpler and better, something which produced greater volumes of reusable code. Those who simply duplicate what others have done without understanding why it was done in in that particular way are in great danger of becoming nothing more than Cargo Cult Programmers. The problem with such people is that because they have been taught by and are surrounded by other Cargo Cult practitioners they cannot tolerate anyone who strays from the path and who dares to think for themselves.
An example of this can be found in a sitepoint thread in 2015 titled Dependency Injection: a discussion of the pros and cons which discussed an article which I wrote in 2011 called Dependency Injection is Evil. One particular critic complained that I was not injecting dependencies into any of my Model classes even though I showed that it was not appropriate to do so. Some of the statements made in that thread caused me 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 was in response to my statement that I never use DI to inject a Model into another Model as I do not have multiple choices for that dependent Model. For example, when I am in the Person object and I wish to obtain the postal address then I access the PostalAddress object, of which there is only one. This means that inserting code to deal with multiple choices when there are no multiple choices would not be appropriate. In fact it would be a violation of YAGNI. His statement clearly demonstrated that he had failed to understand the logic behind the example of the COPY program provided in Uncle Bob's article.
2. You are claiming that an alternative to DI is to use a singleton
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. If the stated purpose of DI is to separate the construction of an object from its use then my alternative is NOT to perform that separation at all. Note also that I do not use the factory method pattern as every one of my Models has a single configuration which is loaded in the class constructor, so I do not need any external code to construct each instance. The only time I require an external configuration is when I define that configuration in my version of a Container before I activate a Controller.
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);
I do not see that these few lines of code constitute separate responsibilities or concerns as described by Robert C. Martin, Martin Fowler or Craig Larman, therefore I see no justification for separating them.
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.
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:
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 Uncle Bob's 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 or View), it has a particular implementation which I have not seen documented anywhere else. That implementation is the subject of this article.
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 "hook" methods which can be overridden in any concrete subclass in order to provide custom processing within that subclass. The developer does not have to write any code to call a customisable method in a subclass as that call is already provided in the superclass.
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 its 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.
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 is being said in this description. It uses a bunch of clever-sounding words which give the appearance of knowledge but which totally fail to point out that DI depends on having modules which are polymorphic and therefore plug-compatible. It says that the conventional dependency relationship is reversed
, but I cannot see how this is achieved. If ModuleA calls ModuleB then ModuleB is the dependency. If ModuleB calls ModuleA then ModuleA is the dependency. The module which is being called is the dependency, and this relationship between the caller and the callee cannot be reversed. 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.
To me that description is utterly meaningless unless it is supported by sample code which proves that its claims have merit. As a pragmatist I cannot follow a principle unless I have good reason to do so, and that description does not provide a good enough reason.
Perhaps this implementation was chosen for the simple reason that in the early compiled and statically typed languages it was only possible to use the new operator with a hard-coded class name. This limitation does not exist in PHP which is interpreted and dynamically typed. It is possible to provide the class name in a string variable instead of forcing it to be hard-coded. Note that the PHP manual states that As of PHP 8.0.0, using new with arbitrary expressions is supported
but this is crap as I was using this technique way back in 2002 with PHP 4.
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 below). 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.
Inversion of Control and Dependency Injection are unrelated principles. Mixing the two up causes nothing but confusion, so anything written by people who add to this confusion is not worthy of consideration and can be ignored.
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 authors 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:
some implementationsas my implementation employs a different (and therefore heretical) technique.
the degree to which the responsibilities of a single module/component form a meaningful unit, so when you consider that constructing an object and calling one of its methods can take a minimum of two lines of code, I fail to recognise how two lines of code, as shown below, can be considered to be separate responsibilities.
$instance = new classname; $result = $instance->method($arg);
The Single Responsibility Principle was first documented by Robert C. Martin, and while he talks about separating concerns such as presentation logic, business logic and database logic, each of those areas of logic requires many lines of code, and only someone suffering from a severe attack of pedantry and dogmatism coupled with a lack of common sense would treat those two lines of code as being unrelated and therefore candidates for separation. As such I treat this wild interpretation of SoC as being nonsensical and therefore without merit.
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 earlier 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 and interchangeable. This situation can only exist if your modules have loose coupling, and this requires the presence of common method names and the absence of code which deals with different property names. 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.
Why should it be necessary to use anything other than the new operator in order to instantiate a class into an object? Who on earth writes classes that require external code to identify how they should be configured? In my framework each concrete table class has only one configuration, and that is handled within the class constructor when it loads the contents of the table structure file into the object's memory. What is the purpose of a constructor if not to construct the instance? The clue is is the name, you numpty. Any code which is necessary to configure an abstract class into a concrete class is contained within the class constructor of the subclass, so all knowledge of how to construct the object is contained within the subclass itself, not in any external code. This follows the principle of implementation hiding which is supposed to be a fundamental part of encapsulation. If I don't need external code to construct an object then what is the benefit of following this pattern? Surely that would be a violation of YAGNI?
4. The receiving "client" (object or function) is provided with its dependencies by external code (an "injector").
There is no rule which states that EVERY dependency MUST be injected by external code. While I agree that there are benefits in doing so when a dependency can be supplied from a number of plug-compatible objects, where there is never a choice between several alternatives then surely the act of adding in code to switch to an alternative which does not exist would be a violation of YAGNI?
Every programmer should be aware that a design pattern does not (or should not) specify an implementation, it simply specifies the objectives that an implementation should follow, but you have to create that implementation yourself. As stated above the DI pattern provides the ability to swap dependent objects at run time
, but it does not specify either how to choose which dependent object should be selected, nor how that choice should be passed down to the object which will use that dependency. The fact that some languages only allow you to inject a fully-formed object is just a limitation of those languages. This restriction does not exist in PHP as it is allowable to instantiate an object from a class name contained in a string variable. I started using this feature in PHP 4 in 2003, so I know that it works. This means that instead of instantiating the dependent object BEFORE it is injected I can simply load a variable with the class name and pass it down to the receiving object where it can be instantiated AFTER it has been injected. This fulfils the objective of the pattern, therefore it cannot be described as wrong. The fact that the implementation is different is irrelevant.
When somebody tells me about a principle or practice which I should be following my first reaction is to seek out the originating document and not to rely on hearsay from an unknown and unreliable source. I prefer to get my information from the horse's mouth instead of from a horse's a***. My research into the The Dependency Inversion Principle led me to the observations which are contained in the introduction.
Later research brought me to discover the Evans Classification which described the difference between entities and services, and also to other papers reinforced my view that while injecting entities into services was an acceptable practice the notion of injection services into entities was not.
Services depends on entities, while the opposite should not happen.
A newable [entity] is a class that can just be instantiated (e.g. with the 'new' operator) as needed in code.This is precisely why I only inject entities into services. I have hundreds of alternative entities (Models) in my application, and each of my Controllers and Views can function with any one of those entities.
An injectable [service] should be injected (typically via constructor injection) in its client.
Do yourself a favor and don't inject Services into newables.
As Uncle Bob's 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 as they all seemed to concentrate on the notion that you could only inject a fully-formed object whereas I had discovered that PHP allowed me to inject just the name of the class file which I could instantiate later. None of the sample code I came across looked as if it could be fitted into my framework without major surgery and without violating the KISS principle. 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. In fact I was underwhelmed. As I investigated further I became even more unimpressed as I realised that instead of starting with the purpose of DI, which is to take advantage of polymorphism, they were all concentrating on how it could (or should) be implemented, which was to inject a fully-formed object. They tried to deduce the purpose of DI by reverse-engineering its implementation, and it was obvious to me that their conclusion was wrong. Because of this I decided not to follow their "advice" as it was obviously based on erroneous assumptions.
The fact that in all early compiled and statically typed languages the only way to inject a dependency was via a fully-formed object I discovered was a limitation of those languages. PHP, being interpreted and dynamically typed, does not have this limitation, so I found a different method which involved injecting nothing more than the name of the class from which the dependent object could be instantiated. Same result, different method, less code. Winner, winner, chicken dinner!
What I found amazing is that in all that I read about dependency injection, even in Uncle Bob's original article, it was never identified that its purpose was to provide a mechanism to take advantage of polymorphism. What is the point of polymorphism if you cannot use it? How many ways are there of using polymorphism? While everybody else is absorbed, perhaps even obsessed, by how it can (or should) be implemented, nobody has made this simple connection. They cannot tell that my implementation is effective, just different, so all they can do is complain about the difference. Because they cannot recognise my implementation as being valid they automatically classify it as being "wrong".
After spending 20 years building enterprise applications with languages such as COBOL and UNIFACE, in 2002 I decided to switch to a new language so that I could build the same type of application for the internet. I chose PHP as it was purpose built for creating dynamic web pages which pulled their content from a relational database. It also introduced me to the black art of Object Oriented Programming (OOP). I did not attend any training courses on OOP as I was already an accomplished programmer who had designed and built both a library of common routines and then a framework in two different languages which had increased the productivity of the entire development team. I felt that I could easily train myself by reading the manual and looking through sample code which I found in books and various online resources.
I should point out that while I had been following the principles of KISS, DRY and YAGNI, as well as the principle of high cohesion as personified in the 3-Tier Architecture, I had no knowledge of such things as design patterns or best practices such as SOLID and GRASP as they were unique to OO languages. That turned out to be a blessing in disguise as I later realised that they were so badly written and open to so much interpretation, and therefore misinterpretation, that the results which they achieved were highly questionable. I discovered that I could achieve better results, i.e. code which was less complex and more reusable, by ignoring them completely and following my own nose. I particularly disagreed with the idea that OOP required a completely different approach to the way that systems needed to be designed simply because I had already learned that the most important part of any database application was the design of the database itself, and once that had been done then the code should be structured around that design. I did not change my design methodology when I switched from COBOL to UNIFACE, and I saw no reason to change it when I switched to PHP. While the syntax of each of those languages may be different, the basic programming principles were the same.
As far as I am concerned Object Oriented programming is exactly the same as Procedural programming except for the addition of encapsulation, inheritance and polymorphism. They are both designed around the idea of writing imperative statements which are executed in a linear fashion. The commands are the same, it is only the way they are packaged which is different. While both allow the developer to write modular instead of monolithic programs, OOP provides the opportunity to write better modules with more reusability.
My first project with PHP involved building a small proof of concept (POC) in the form of a small sample application which I published in November 2003. This proved to me how straightforward it was to write reusable code which could read database data and convert it into HTML using the XSL templating engine. This was so successful that I went ahead and produced a third version of my framework to provide standard functionality such as a login screen, dynamic menus and Role Based Access Control (RBAC) which were common to all the database applications which I had developed previously. I released this framework as open source in 2006 under the name RADICORE.
Below is a small diagram of the structure used in the RADICORE framework. It started by being an implementation of the 3-Tier Architecture, but later evolved to be combined with the Model-View-Controller (MVC) design pattern, as shown below in Figure 1:
Figure 1 - MVC plus 3 Tier Architecture
Note that there is a more detailed diagram in RADICORE - A Development Infrastructure for PHP.
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:
You should notice that the framework does not require any component to be hand-crafted by the developer. All Controllers, Views and DAOs are built into the framework, and all Models are generated by the framework and already contain 100 percent of the boilerplate code which is inherited from an abstract class. This includes all standard data validation, with the developer only needing to insert the code for any non-standard business rules into the various "hook" methods which have been provided.
In answer to the question How effective is the RADICORE framework?
I point to the fact that in 2007 I started to build my first ERP package, which was called TRANSIX, by picking six database designs from Len Silverston's Data Model Resource Book, then generating the class files and user transactions from the database schemas. The real effort involved adding in the business rules to the "hook" methods and after six months I had a prototype which I could demonstrate to a client. That is six months for six databases, which is an average of one month per database. If you think you can match that then prove it by taking this challenge.
While TRANSIX started off with 10 subsystems, 300 database tables and 2,500 tasks, this has grown into a larger version called GM-X which has 20 subsystems, 500 tables and 4,500 tasks.
Note that there are significant differences between my approach and the one taught by all the OO "experts":
There are several other "best practices" which I do not follow for various reasons, but they are documented elsewhere on my web site.
Since a major motivation for object-oriented programming is software reuse it should follow that the more code you can reuse then the more successful you are at OOP. The more code you can share then the less code you have to write and the quicker you can get the job done. It is all about striking a balance between the code that you *DON'T* have to write (because it already exists in a form which is reusable) and the code that you *DO* have to write (because it is unique and does not exist until you write it). If the ultimate goal is to spend the minimum amount of time in writing boilerplate code so that you can spend the maximum amount of time on the business logic, then the fact that the standard modules within the RADICORE framework, as shown below, provide 100 percent of the boilerplate code should be significant.
The high amount of reusability in my framework is directly attributable to just one thing - dependency injection, which in turn is a product of polymorphism, which in its turn is the result of every concrete table class inheriting its boilerplate code from an abstract table class. Every table class, which is the Model in MVC, then supports the same set of methods, which, in turn, means that every Controller calls the same set of methods irrespective of which Model it is calling. Note that every method called by a Controller on a Model is an instance of the Template Method Pattern.
Instead of having a single Controller being responsible for all the user transactions for a particular Model, which results in tight coupling, I was able to create a number of Controllers each of which performs a single transaction on an unknown table. Each transaction requires a particular set of methods, but as these methods are the same for each table the only variable within a Controller is the table identity, and this is supplied at run time via dependency injection.
Instead of having a separate View object for each web page which contains hard-coded references for each field/property I have a single object which can extract the data from any Model using a single getFieldArray() method. Standard code can then copy the contents of this array into an XML document without the need for any hard-coded property names.
When I started teaching myself PHP I noticed straight away that procedural and object oriented programming are the same in that they are both designed around the idea of writing imperative statements which are executed in a linear fashion. The only difference is the way that the code can be packaged. In procedural programming a function can only be defined once, and after being called it disappears from memory. In object oriented programming several functions can be grouped together in a class, and the same function name (now called a method) can be duplicated in any number of classes. A class must be instantiated into an object before any of its methods can be called. After a method has been called the object still resides in memory, and this allows the data within the object to be viewed or modified by calls to other methods. Methods can be called on an object for as long as that object exists within memory, which is until it is destroyed.
By reading the PHP manual I learned the mechanics of encapsulation and inheritance. I also consulted a few online resources and bought a few books to see sample programs written by others. Sadly none of these provided examples of polymorphism or how it could be used, so I left that for later. I had read that the main motivation for using OOP was to increase code reuse and decrease maintenance, so that is what I strived to achieve. After I had built several objects which shared the same method names I realised that those methods could be defined once in an abstract class and shared through inheritance. I also saw that a piece of code which called those methods could be made to function with any object, so I tried several experiments until I found a simple mechanism to achieve maximum reusability. That simple method is the subject of this article.
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:
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 to 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 'classes/person.class.inc'; // This identifies the Model class require 'screens/person.detail.screen.inc'; // This identifies the XSL stylesheet $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 (or should know) 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 below in 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 operate on any Model class. It performs the following simple steps:
$fieldarray as both an input and an output argument. This means that none of these methods is tied to a particular set of column names.Each Controller can operate on any table class and can have no more than one View. There is a central library of 45 reusable Controllers, one for each of my Transaction Patterns.
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 thisclass 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
This functions as follows:
Note here that the container has to be reconstructed at run time, which requires code to perform that reconstruction.
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:
<table>.class.inc and exists in the subsystem's classes subdirectory.screens subdirectory.INCLUDES directory which is identified using the include_path directive.Instead of having two pieces of code to first build the CONTAINER before instantiating the CONTROLLER so that the CONTAINER can be injected into it 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 activating the component that will use those dependencies. This achieves the same result as the orthodox method as shown in Figure 2, but with fewer and simpler components. Note that the component identified as SCRIPT #1 is no longer required.
Figure 3 - Diagram of my heretical DI Container
This functions as follows:
Note the following:
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 the same set of practices, but only when appropriate and using a different interpretation and a different implementation, one that, in my opinion, produces the best results. The main motivation for object oriented programming is to create more reusable code as this leads to less maintenance, so 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:
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 requiring its own setter and getter, 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:
While these transactions are fully functional in that they automatically perform primary validation, additional business logic can be added in afterwards by inserting the relevant code into any of the predefined "hook" methods
This means then that if I have 45 Controllers which can be reused with any of my 500 Model classes I therefore have 45 x 500 = 22,500 (YES, TWENTY TWO THOUSAND FIVE HUNDRED) opportunities for polymorphism and dependency injection.
I could not have created such huge levels of reusability if I had blindly copied other people's implementation of "best practices", so being different does have its advantages.
Here endeth the lesson. Don't applaud, just throw money.
| 15 Jun 2026 | Rearranged the sequence of several sections into a more logical order. |
| 04 May 2026 | Added Overview of the RADICORE framework
Added What Dependency Injection is NOT Renamed What is Dependency Injection (DI)? to What Dependency Injection IS |