Dependency injection

Dependency injection is a technique where one object supplies the dependencies of another object. An injection is the passing of a dependency to a dependent object that would use it. Passing the service to the client, rather than allowing a client to build or find the service, is the primitive requirement of the pattern.

This primitive requirement means that using values produced within the class from new or static methods is prohibited. The class should accept values passed in from outside.

The intent behind dependency injection is to decouple objects to the extent that no client code has to be changed simply because an object it depends on needs to be changed to a different one.

Dependency injection is one form of the broader technique of inversion of control. Rather than low level code calling up to high level code, high level code can receive lower level code that it can call down to. This inverts the typical control pattern seen in procedural programming.

Dependency injection supports the dependency inversion principle. The client delegates the responsibility of providing its dependencies to external code (the injector). The client is not allowed to call the injector code. It is the injecting code that constructs the services and calls the client to inject them. This means the client code does not need to know about the injecting code.

There are three common means for a client to accept a dependency injection: setter-, interface and constructor based injection. Setter and constructor injection differ mainly by when they can be used. Interface injection differs in that the dependency is given a chance to control its own injection. All require that separate construction code (the injector) take responsibility for introducing a client and its dependencies to each other.

For example, consider a Car object.

A Car depends on wheels, engine, fuel, battery, etc. to run. Traditionally we define the brand of such dependent objects along with the definition of the Car object.

Without Dependency Injection (DI):

Here, the Car object is responsible for creating the dependent objects.

What if we want to change the type of its dependent object – say Wheel – after the initial IndianWheel() punctures? We need to recreate the Car object with its new dependency say JapaniWheel(), but only the Car manufacturer can do that.

Then what does the Dependency Injection do us for…?

When using dependency injection, objects are given their dependencies at run time rather than compile time (car manufacturing time). So that we can now change the Wheel whenever we want. Here, the dependency (wheel) can be injected into Car at run time.

After using dependency injection:

Here, we are injecting the dependencies (Wheel and Battery) at runtime. Hence the term : Dependency Injection.

Constructor

What does Constructor mean?

A constructor is a special method of a class or structure in OOP that initializes an object of that type. A constructor is an instance method that usually has the same name as the class, and can be used to set the values of the members of an object, either to default or to user-defined values.

Constructors are not called explicitly and are invoked only once during their lifetime. In the case of a hierarchy of classes where a derived class inherits from a parent class, the execution sequence of the constructor is a call to the constructor of the parent class first and then that of the derived class.

Constructors cannot be inherited.

A constructor can be declared using any of the access modifiers. It is mandatory to have a constructor with the right access modifier. However, the compiler supplies a default if an access modifier is not defined in the class. If a constructor is declared as private, the class cannot be created or derived and hence cannot be instantiated. Such a constructor, however, can be overloaded with different sets of parameters. 

Constructor design:

  • When using derived class constructors, the parent class constructor should be passed the correct parameters.
  • Better code maintainability comes from having the initialization and other related logic in one main constructor and cross-calling this constructor from other overloaded constructors.
  • Logic involving specific operations that need to be executed at a particular event in an application – such as opening a database connection – should not be written in a constructor.
  • Because a constructor cannot return a value to the calling code, it is a good practice to throw an exception when a failure is encountered.

Dependency injection in PHP

Dependency Injection is a software design pattern that allows avoiding hard-coding dependencies and makes possible to change the dependencies both at runtime and compile time.

By using Dependency Injection we can write more maintainable, testable, and modular code. All projects have dependencies. The larger the project the more dependencies is it bound to have; now having a great number of dependencies is nothing bad by itself however how those dependencies are managed and maintained is.

Dependency Injection is not a new pattern and it has been commonly used on many languages like Java, but this pattern is somewhat new in the PHP world and it’s gaining traction quickly thanks for frameworks like laravel

Let’s exemplify these concepts by creating a pair of classes first without dependency injection and then rewriting the code to use the dependency injection pattern; since I’m primarily a Magento developer I’ll be really original (wink, wink) and create a Product and a StockItem class.

At first glance the code looks pretty normal and it’s what many PHP developers would call good code, however if we take a closer look at it using the S.O.L.I.D principle we can see that the code actually has many problems:

  • The StockItem is tightly coupled with the Product class, and while this might not look bad on this particular example. Let’s imagine that we made a change to the StockItem class to include a new parameter, we would then have to modify every single class where the StockItem object was created.

  • The Product class knows too much, in this case the stock status and quantity, let’s say that our application can handle inventories from multiple sources and stores but for the same product. With that in mind it would be in our best interest to make the Product class know less about its inventory.

  • We just made our life harder when it comes to unit testing the code. Since we are instantiating the stockItem inside the constructor it would be impossible to unit test the Product class without also testing the StockItem class.

Let’s Inject something!

In the other hand by using dependency injection we can correct most of these problems, let’s take at the same code but using dependency injection:

Constructor Injection

By using dependency injection we have more maintainable code, in the previous example we are using a type of dependency injection normally referred as Constructor Injection. By doing a simple change we can reduce the level of complexity of our code and improve the overall quality; not to mention that now we can easily run unit tests.

Constructor injection is by far the most common method used and there are several advantages by using this particular type of injection:

  • If the dependency is required by the class and cannot work without it, by using constructor injection we guarantee that the required dependencies are present.

  • Since the constructor is only ever called when instantiating our object we can be sure that the dependency can’t be changed or altered during the object lifetime.

These two points make Constructor Injection extremely useful, however there is also a few drawbacks that make it unsuitable for all scenarios:

  • Since all dependencies are required, it’s not suitable when optional dependencies are needed.

  • While using class inheritance trying to extend and override the constructor becomes difficult.

Setter Injection

Another common type of dependency injection is called setter injection and the same code as above would look something like this:

As we can see, with Setter Injection the dependencies are provided to our class after it has been instantiated using setter methods. Setter Injection has a few advantages:

  • Allows for optional dependencies and the class can be created with default values.

  • Adding new dependencies is as easy as adding a new setter method and it won’t break any existing code.

Setter Injection might be more suitable for situations where more flexibility is required.

Differences between abstract class and interface in PHP

  1. In abstract classes this is not necessary that every method should be abstract. But in interface every method is abstract.
  2. Multiple and multilevel both type of inheritance is possible in interface. But single and multilevel inheritance is possible in abstract classes.
  3. Method of php interface must be public only. Method in abstract class in php could be public or protected both.
  4. In abstract class you can define as well as declare methods. But in interface you can only defined your methods.

Traits in PHP

One of the problems of PHP as a programming language is the fact that you can only have single inheritance. This means a class can only inherit from one other class.

However, a lot of the time it would be beneficial to inherit from multiple classes. For example, it might be desirable to inherit methods from a couple of different classes in order to prevent code duplication.

This problem can lead to class that has a long family history of inheritance which often does not make sense.

In PHP 5.4 a new feature of the language was added known as Traits. A Trait is kind of like a Mixin in that it allows you to mix Trait classes into an existing class. This means you can reduce code duplication and get the benefits whilst avoiding the problems of multiple inheritance.

PHP Traits?

A Trait is simply a group of methods that you want include within another class. A Trait, like an abstract class, cannot be instantiated on it’s own.

An example of a Trait could be:

You could then include this Trait within other classes like this:


Now if you were to create new objects out of these classes you would find that they both have the share() method available:

How do Traits work?

As you can see from the example above, both the Post and the Comment objects have the share() method available despite not having that method defined.

A Trait is basically just a way to “copy and paste” code during run time.

This means the Trait is copied in to the Post and Comment classes so when you instantiate a new instance, the share() method code will be available.

How are Traits different to Abstract classes?

A Trait is different to an Abstract class (What are Abstract classes?) because they do not rely on inheritance.

Imagine if the Post and the Comment class had to inherit from a Social class. We are most likely going to want to do more than just share posts and comments on social media websites, so we’ll probably end up with a complicated inheritance tree like this:


This complicated inheritance is pretty nasty, but it also adds complication when a simpler object does not have a similar inheritance structure. For example, if we had a Message object that shouldn’t allow social sharing, then this object would require a slightly different inheritance structure.

How are Traits different to Interfaces?

Traits kind of look a lot like Interfaces. Both Traits and interfaces are usually simple, concise and not much use without an actual implemented class. However the difference between the two is important.

An interface is a contract that says “this object is able to do this thing”, whereas a Trait is giving the object the ability to do the thing.

For example:


In this example we have a Sociable interface that states that the Post object is able to like() and share().

The Sharable Trait implements the share() method and the like() method is implemented in the Post class.

So as you can see we could type hint the Post object to see if it is sociable (it implements the Sociable interface), whilst the Trait defines a reusable method that we can then mix in to other similar classes:

Benefits of Traits?

The benefit of using Traits is that you reduce code duplication whilst preventing complicated class inheritance that might not make sense within the context of your application.

This allows you to define simple Traits that are clear and concise and then mix in that functionality where appropriate.

Drawbacks of Traits?

However with that being said, there are possible drawbacks when using Traits too.

Traits make it very easy to write bloated classes that have too much responsibility. A Trait is essentially a way to “copy and paste” code between classes. By having a way to very simply add another group of methods to a class, it’s very easy to diverge from the single responsibility principle.

Other drawbacks to using Traits are not being able to see all the methods of a class when looking at the source code as well as method conflicts or duplication of logic.

I think Traits, when used correctly, are a fantastic tool to have at our disposal. However, Traits can also be crutch for lazy programming. It’s very easy to just add a Trait to solve your immediate problem. Often composition is the better approach over inheritance or using a Trait.

What are typical situations for using Traits?

So what would be a typical situation when using a Trait would be a good idea?

Well, I think Traits are an excellent way to reuse a chunk of code between a set of similar classes that should not inherit from the same abstract class.

Using the social application from earlier, imagine we had objects for Post, Photo, Note, Message and Link. For the most part, these objects are fairly interchangeable within our system as they are typically created and interacted with between users.

However, Post, Photo, Note and Link are all objects that are publicly shareable between users, whereas Message objects are private messages that are not made public.