Dependency Injection: a discussion of the pros and cons

You forget that when PHP 5 came out it took several years to become widespread, so I had no choice but to support both PHP 4 and PHP 5 with the same codebase for my open source framework. It is more than likely that I no longer have any customers who are still using PHP 4, but I have still done nothing to my codebase to make it PHP 5 only.

And there we have it, folk’s. Tony doesn’t even want to use any of the PHP5 features. If we can’t convince him about autoloading, visibility, iterators or any of the other useful features from 5.0+ then making him understand the benefits of DI simply isn’t going to happen.

Let’s put it this way, the benefit of autoloading is objective, measurable in both development time and lines of code yet Tony won’t use that. Tony you have now officially mooted your opinion on, well, everything.

Sorry, I just realized I missed this, but aren’t you missing one of the points of a singleton if you are always clearing it out?

Plus doesn’t that require more code than simply saying “new $class” if you have to clear out your singleton each time you want to use it?

Again, not an attack at your code, this is conceptual, I’m purely looking at a discussion around a statement that made it unclear for me or provoked an internal thought. Please DO NOT take this personally or related to your framework – that is not the intent!

I’ve used singleton patterns in the past but it was because I needed to deal with a third party DLL that can only have one instance running. The DLL required you to invoke commands against it in specific order, so we queued all transactions until the prior one completed.

Each time we needed to interact with it, the remnants of the prior usage may be required for the next command to function properly.

It is true that there are other ways to deal with this, but at the time I was a part of this, using a singleton was considered the “best” approach given the existing code base and the time we had to implement it.

In the end, 2 years later, we rewrote the whole thing, and got rid of the singleton, as 1) the third party gave us a better DLL that wasn’t restricted to one instance and 2) we learned a lot in those 2 years and found better ways of handling the scenario.

My statement is based on the fact that I have been maintaining and enhancing my application for nearly 10 years, and in that time I have NEVER had to change a dependency in any of my Model classes.

Telling me to refactor my code to provide a facility that I will never use, thus making that refactoring exercise a total waste of time, is not a good idea in anybody’s book.

Incorrect. You think it is faster and has fewer lines of code, but your sample code is inadequate and simply will not work for me, as I explained in post #102 and #115

Why is @TomB’s considered “tight coupling” but yours isn’t? DI is meant to be loose coupling…

The burden of proof is on you to support this claim, you still have not provided a code example which does so.

Tony. Please either start providing code examples to back up your points or stop responding entirely because your words are meaningless without evidence.

As I mentioned before it’s like a drug company saying “Of course my drug is better! No, you can’t see the clinical trials!”

I have provided all the code samples that I am willing to provide. You yourself have posted a sample of my code and started criticising it. I have been responding to that criticism as is my right. If you do not agree with what I have to say then let us agree to disagree and stop arguing.

I have provided all the code samples that I am willing to provide.

Then this discussion is over because they are inadequate. Your argument rests on “i can’t do that in my framework so i did this instead” which potentially highlights an issue with the framework rather than the matter at hand. Unfortunately without decoupling the concept being discussed from your framework it’s impossible to work out whether the concept you’re proposing as an alternative to DI is worthwhile or not.

Given a clean slate I would always start off with the simplest solution (which would automatically exclude DI and a huge assortment of design patterns) and only add levels of complexity where they actually provided something of benefit which was worth the effort.

Please do not talk to me AGAIN about “best practices” as we both know that your idea of what is best is totally different from mine.

Finally you have aid something with which I agree - that implementing your ideas on DI in my existing code would cause me problems.

I have been maintaining the same framework and the same application for over 10 years, and quite often when I look at a piece of my old code in order to deal with a bug (yes, I admit to having bugs in my software on occasions) or a change request I think to myself “Shall I bodge this code to make it work, or shall I refactor it to make it work better” I always take the time to think about the refactoring options and always choose the one which produces the best result for the long term. Sometimes the “best result” takes quite a bit longer than a “quick bodge”, but I learned over 20 years ago that a quick bodge often has very large teeth that will bite you in the a*** sooner or later.

What I don’t do is pick a piece of code at random and try to refactor it for the sake of refactoring it.

I never said DI was “inferior” just “unnecessary” in some circumstances. There is a difference.

It’s not about not wanting to use, it’s about not needing to use any of those features. I consider all these new features to be nothing more than optional extras" explained in http://www.tonymarston.net/php-mysql/minimalist-approach-to-oop-with-php.html#oop.optional-extras

Incorrect. I am using a singleton as I was informed a long time ago that reusing an existing object was quicker than instantiating a new one. The fact that I don’t carry forward the state of the singleton instance is irrelevant. Has anyone got any new evidence to say that creating a brand new instance is no more expensive than pulling an existing copy from memory?

If you’ve truly had enough of this topic you can select “Muted” after the last post and never need be bothered by it again.

If his Controller has the name of the Model hard-coded into it, as well as all the names of the dependents of that Model, it means that the Controller can only be used with that one Model, and that Model can only be called from that Controller. This is a classic example of tight coupling as those two components - the Controller and the Model - are tied together and cannot be reused with other components.

Now compare this with my implementation: any Controller can be used with any Model, and any Model can be used with any Controller. Any View can be used with any Model and any Model can be used with any View. This is a classic example of loose coupling as no Controller is tied to a particular Model and vice versa.

If you say that DI is meant to promote loose coupling then can you explain to me why in @TomB’s example this is not the case? It only seems to create loose coupling between the Model and its dependents, not the Controller and the Model.

Just as your code samples are just as inadequate for me.

Incorrect. I am saying that I use DI in my framework where I consider DI to be appropriate, and I choose not to use DI in those places where I consider it to be inappropriate.

You still don’t understand that the alternative to using DI is NOT to use DI. The discussion should not be centered on how I have implemented the NO DI option but why I have chosen not to use DI and is there any logic to my reasoning. You simply cannot accept that my reasoning is valid and keep insisting that I MUST use DI irrespective of the costs or the benefits. It is this attitude that I object to.

I had new Controller(new Model)) how is that hardcoded?

It’s not about not wanting to use, it’s about not needing to use any of those features. I consider all these new features to be nothing more than optional extras" explained

The following are also “optional”:

  • functions
  • loops
  • arguments
  • arrays
  • objects
  • databases
  • the mysql extension
  • include/require statements

These features, and the others you label “optional” are there to make your programs better by either reducing repetition or making complex tasks less difficult. They are just as “optional” as everything else you listed and they serve exactly the same ends. Choosing not to use these features is choosing to purposefully limit yourself and limit the quality of the applications you produce.

Imagine making a program without arrays or if statements or functions. The quality of your application will suffer as a result. You lose just as much if not more benefit by not fully utilising the other features available to you. You are the one who loses out by choosing not to use them.

Sure you can make a program that doesn’t use a database, or functions and everything is in a single file but it’s objectively inferior. The same is true if you choose not to use OOP and other PHP5 features which are available to you as a programmer.

It’s like building a house but saying “I only want to use straw. Bricks and Metal are optional!” you can do that but the house made of bricks will last longer and be more robust, you can also build it taller and larger.

Your reasoning is not valid. “NO DI” is not an alternative to DI. It’s like saying “No if statements is alternative to if statements”. DI solves a necessary problem, if you don’t use DI you must solve the problem in a different way and you have REPEATEDLY refused to demonstrate how while simultaneously claiming that you dont need di!

No. He is passing it in as an argument, much like you use global scope to pass your model name.

Yes, I can forget that, as the first release of PHP5 was over 10 years ago. The fact your footnotes are still there saying you are still supporting PHP4 is a blaring communication for anyone who knows anything about PHP saying “avoid my work, as it is completely archaic and not worth your time!”

On a much lighter note. I really love this video session teaching DI and DI containers. It is also free to watch too and I’d suggest it for anyone wanting to know the advantages and disadvantages of DI and DI containers (and why I like the lesson, because it doesn’t just say using DI is perfect, which I think Tony can respect too. :wink:)

Scott

Tony to demonstrate once again based on your limited code examples that my method has looser coupling.

You presented this code:

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

include file:

require_once "classes/$table_id.class.inc";
$dbobject = new $table_id;
$result = $dbobject->doSomething();

I suggested you could achieve the same thing with DI after you said and this is a direct quote:

I’m afraid that this method of injecting dependencies just will not work in my framework because it changes the coupling between the Controller and the Model from very low to very high.

A claim that you have repeated even after I gave you two examples where this is not the case:

new Enquire1(new Person));

The advantage of this method is that I can also do this:

new Enquire1(new Person(new Address));

This is more loosely coupled because I can choose the dependency $address at the top level. Your code is tightly coupled because it always uses the same address class.

You claim not to want this extra level of flexibility which is fine, but FYI it can be achieved easily with your original code anyway:

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

include file:

require_once "classes/$table_id.class.inc";
require_once "classes/$dependency.class.inc";
$dbobject = new $table_id(new $dependency);
$result = $dbobject->doSomething();

I never got a response to this other than a flat out lie that “It only seems to create loose coupling between the Model and its dependents, not the Controller and the Model.”

Again, we’re talking at cross purposes here because you haven’t clearly identified which part of the code you are referring to as the controller. I am assuming your controller is the std.enquire1.inc file.

However, this is an aside to the point. You keep claiming that:

I’m afraid that this method of injecting dependencies just will not work in my framework because it changes the coupling between the Controller and the Model from very low to very high.

and

If his Controller has the name of the Model hard-coded into it, as well as all the names of the dependents of that Model, it means that the Controller can only be used with that one Model, and that Model can only be called from that Controller. This is a classic example of tight coupling as those two components - the Controller and the Model - are tied together and cannot be reused with other components.

which is a flat out lie as it’s been shown otherwise. I felt I needed to repost this as clearly you missed or misunderstood it the first time around.

With that said, Before doing anything else please respond to the following posts of mine which you chose to ignore as they are important:

This one based on your own code example:

the ones I reiterated above:

http://www.sitepoint.com/community/t/dependency-injection-a-discussion-of-the-pros-and-cons/112088/122?u=tomb

this one:

http://www.sitepoint.com/community/t/dependency-injection-a-discussion-of-the-pros-and-cons/112088/143?u=tomb

and the second part very well expressed post by cpraido that hits the nail on the head about conceptualisation

http://www.sitepoint.com/community/t/dependency-injection-a-discussion-of-the-pros-and-cons/112088/153?u=tomb

Caveat

If you respond by saying that my example doesn’t work you must explain why with a code example of where it falls short. The simplest way is to copy/paste my code and highlight the flaws in it or alter it.