Magento 2 – Dependency Injection Constructor Arguments

dependency-injectionmagento2object-manager

I have been playing around with Magento 2. There are some things which I don't understand yet. As far as I know so far is that the object manager automatically inserts the right objects to the constuctor. I have some questions regarding this.

I have a controller which extends the following class:

\Magento\Framework\App\Action\Action

When I open this class I see that the __constuctor class has one argument and it expects to be an instance of the Context object.

Now for learning purposes i did this to see with is being injected (it doesn't take more then two arguments by default).

public function __construct($a, $b)
{
    var_dump(get_class($a));
    var_dump(get_class($b));
}

It outputs the following

string(34) "Magento\Backend\App\Action\Context"
string(41) "Magento\Framework\View\Result\PageFactory"

Why are these objects injected? Where can I see which objects I can pass in my constuctor. I couldn't findt any hints in the parent class. I suppose it is dependend on the class I extend?

What happens when I extends below class? And how does the system (and I) know what will be injected?

\Magento\Sales\Controller\Adminhtml\Order\AbstractMassAction

What I am looking for in an answer is not a solution or explaination for this specific example. Moreover I am looking for an overall explaination how I can understand the system better and where I can lookup what I should or must pass as an argument.

Best Answer

I haven't actually tracked this down through code, but here's how I've come to reason about it, and the behavior described below appears to be true (even if the behind the scenes code used by the object manager is different). That said, your question leaves some important details out and is a little vague -- see comments below for some requested clarification that might clear things up.

When the object manager instantiates an object, it looks at your class's __construct method. If your class doesn't have a __construct method, then it looks at the next class's __construct method, etc. until it finds a class with a __construct. Once found, it uses those constructor parameters, and those paramaters only, to build a list of parameters to inject.

Put another way, the object manager will inject the parameters in the constructor PHP would normally call. Remember, PHP only calls one constructor. If you want a parent's constructor class to be called, you need to do parent::__construct(...). This means if the parent class needs a specific list of parameters, its your job to ensure they're also injected in your constructor (so that you can pass them on with parent::__construct).

Regarding your specific questions

Now for learning purposes i did this to see with is being injected (it doesn't take more then two arguments by default).

Your testing methodology seems like it might be a problem here. I tried creating a __construct method in a custom frontend controller that looked like this

public function __construct($a, $b)
{
    var_dump(get_class($a));
    var_dump(get_class($b));
}

And Magento/PHP yelled at me

Missing required argument $a of Pulsestorm\Commercebug\Controller\Lookup\Index

It's also unclear from your questions if these were frontend or backend controllers. If you include more specific code and expand on the steps you used to create your controller, someone may be able to help you understand why the constructor receives a Context object and a page factory object

Regarding the Magento\Sales\Controller\Adminhtml\Order\AbstractMassAction class: If your class extends this class, Magento will inject what parameters are in your __construct method. If your class doesn't have a __construct method, they you don't need to worry about what's injected. Magento will handle it for you via the parent class.