(Starting) Using Dependency Injection in Magento 2

One of the biggest switches you will experience when moving from Magento 1 to Magento 2 is inversion of control.  This is a very different concept to get used to but once you have it you will be a very happy person.  Maybe.  At least I was.  Understanding how to use dependency injection and understanding how dependency injection works are two completely different things of which the former is probably more important if you are new to it.

I wrote an introduction to Dependency Injection for Zend Framework a while back and was able to work out some of the kinks in my understanding of how a DI container worked with 4 blog posts.  It took a while for me to get it but much of what I learned for Zend Framework does directly apply for Magento 2.

Dependency Injection is handled in Magento 2 via the class Magento\App\ObjectManager.  And if you look at that from within the context of Magento 2 you are probably pooping your pants.  200+ class instances, configuration options, dogs and cats living together.

But is it really that difficult?  Let’s start with a little sample script.

1
2
3
4
5
6
7
8
use Magento\App\ObjectManager;
require_once 'app/bootstrap.php';
 
class Test {}
 
$om = new ObjectManager();
$test = $om->get('Test');
echo get_class($test);

We define a class called Test and create an instance of the ObjectManager.  We then ask the object manager for an instance of the class test and echo it out.  When we do we get

Test

OK.  How did it know about the class Test?  It didn’t.  You did.  You knew you needed an instance of Test and you simply asked the DI container for one.  It did a little magic on the backend on gave you exactly what you asked for.

So why would you do this instead of  just calling “new”?

Ahh, that is where the fun comes in.  What if your class Test had a dependency on another class called Test2 which has a method “helloWorld” that it requires?  So we will

  1. Create a class called Test2
  2. Add a method to that class called helloWorld()
  3. Declare our dependency in the constructor of the class Test
  4. Define a method Test::getOutput() which calls Test2::helloWorld()
  5. profit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
use Magento\App\ObjectManager;
require_once 'app/bootstrap.php';
 
class Test2
{
  public function helloWorld()
    {
      return 'hello world';
   }
}
 
class Test {
 
  protected $test2;
 
  public function __construct(Test2 $test2)
  {
    $this->test2 = $test2;
  }
 
  public function getOutput()
  {
    return $this->test2->helloWorld();
  }
}
 
$om = new ObjectManager();
$test = $om->get('Test');
echo $test->getOutput();

When we call this code we get the following output

hello world

“Wait”, you might be thinking.  “Dependency Injection is supposed to be hard!”

Well, it can be, particularly when you need to start configuring the object instances.  However, from a basic perspective what you see here is what Dependency Injection is all about.

We will continue to dive into deeper Dependency Injection in Magento 2 as time goes on, but this is a good place to start with.  If you are not familiar with DI you will probably have a bunch of questions.  We will get to those as time goes on.

[UPDATE]

I was (correctly) notified on Twitter that I needed to be careful not to mix Dependency Injection and a Dependency Injection Container.  Yes, I mixed the concepts; but for good reason.  If you were to look at my code examples and remove the reference to ObjectManager; meaning that you directly injected the dependency you would be using Dependency Injection.  e.g. new Test(new Test2)).  Technically, that is Dependency Injection.  A Dependency Injection Container is when you ask a central object for an instance of a class at IT satisfies the dependencies.

In Magento 2, however, while the two are technical separate concepts they will, in 99.999% (five 9’s) of the scenarios, be married.  That said, if you are going to be building unit tests for your models, and you should, then understanding the distinction is important.  You might use the DIC to contain mocks or you might directly inject the mocks yourself.  I don’t know which way is best at the moment.

1 comments
lsmith
lsmith

If you need to make an instance of or mock the container in a unit test, its a code smell. It will often mean that you are using your DIC as a service locator and not for proper DI.

Trackbacks

  1. […] Schroeder is continuing his current trend of posts with another new one about Magento 2 and using deendency injection and how to use it inside your Magento extension […]

Post Navigation

Web Analytics