Ok, so yesterday we had a big talk with other people from the Magento community regarding the direct use of the ObjectManager in classes/templates.

I'm already aware of the reasons why we shouldn't use the ObjectManager directly, quoting Alan Kent :

There are several reasons. The code will work, but it is best practice to not reference the ObjectManager class directly.

  • Because we say so! ;-) (better expressed as consistent code is good code)
  • The code could be used with a different dependency injection framework in the future
  • Testing is easier - you pass in mock arguments for the required class, without having to provide a mock ObjectManager
  • It keeps dependencies clearer - it is obvious what the code depends on via constructor list, rather than having dependencies hidden in the middle of the code
  • It encourages programmers to think about concepts like encapsulation and modularization better - if the constructor gets big, maybe it is a sign the code needs refactoring

From what I've seen in StackExchange, a lot of people tend to go for the easy/short/not recommended solution for example something like this:

<?php 
//Get Object Manager Instance
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();

//Load product by product id
$product = $objectManager->create('Magento\Catalog\Model\Product')->load($id);

Instead of going through the painful but recommended process of:

  • creating a module
  • declaring preferences
  • inject dependencies
  • declare a public method

However, and here comes the dilemma, Magento 2 core files often call the ObjectManager directly. A quick example can be found here: https://github.com/magento/magento2/blob/develop/app/code/Magento/GoogleOptimizer/Block/Adminhtml/Form.php#L57

So here are my questions:

  • Why is Magento doing what they recommend us not to do ? Does that mean there are some cases where we should use the ObjectManager directly? If so, what are those cases?
  • What are the consequences of using the ObjectManager directly?
  • 4
    Check this out: magento.stackexchange.com/q/28617/146 – Marius May 26 '16 at 11:29
  • 3
    Relevant link: mwop.net/blog/2016-04-26-on-locators.html. The relevant bit of it would be The intent of zend-servicemanager is for use as an Inversion of Control container. It was never intended as a general purpose service locator [...]. Which it applies to M2, too. Also check the There are valid use cases section, which, again, applies here, too. – nevvermind May 26 '16 at 12:29
  • 3
    There was some period of M2 development when OM was already there, but whole magento was not yet changed to use constructor injection. At that point many people replaced Mage::getSingleton() with ObjectManager::getInstance()->get(). Most of such usages were introduced at that period. Later all Mage::getSingleton() calls were replaced with constructor injection by a tool, but tool did not recognized ObjectManager::getInstance(), so it did not replace it with constructor injection. – Anton Kril Oct 6 '16 at 11:03
  • 3
    Possible duplicate of Magento 2 Helper instance – Teja Bhagavan Kollepara Feb 20 '17 at 12:08
  • 3
    @TejabhagavanKollepara did you read both questions ? There are similar but far from being duplicate from each other – Raphael at Digital Pianism Feb 20 '17 at 12:15
up vote 78 down vote accepted

You should not use the ObjectManager directly!

Exception from the rule are:

  • in static magic methods like __wakeup, serialize, etc
  • in case you should make backward compatibility of constructor
  • in global scope, like in fixtures of integration test.
  • in class that needs only for creation of object like factory, proxy , etc

You should never use \Magento\Framework\App\ObjectManager::getInstance().
It defeats the purpose of dependency injection. We're back at Mage::getModel().
Object manager should be used only in factories and then as injected in a constructor.

The advantage of using this is less code to write. But this does not make it OK.
The fact that this is still used in the core, is because it didn't get refactored yet. I hope it will be.

  • 4
    So we both agree that Magento code is doing it wrong right ? – Raphael at Digital Pianism May 26 '16 at 11:41
  • 8
    right. they are wrong :). – Marius May 26 '16 at 11:43
  • I don't think they're using wrong. They're using it when necessary: when dynamic resolving is needed (plugins, especially) and when keeping BC on immediately-deprecated methods. – nevvermind May 26 '16 at 12:32
  • 2
    @nevvermind Using a factory. You use di.xml to create a key => class name map and inject that map in to constructor of the factory and use the factory to instantiate the class through objectmanager – Marius May 26 '16 at 15:07
  • 2
    @nevvermind But a Magento employee's opinion outranks your opinion. You have an answer above from KAndy that states in bold letter "you should not use the object manager directly": magento.stackexchange.com/a/117103/146 I guess that kind of clears the fog on the issue. – Marius May 26 '16 at 15:31

So why does M2 sometimes access object manager directly when we recommend against it?

Brutal answer: M2 is a port of M1 - not a complete rewrite. So don't assume that all the M2 code is perfectly ported yet (unfortunately). Just because you find something in the M2 code base, that does not mean "its the best way to do it". Sometimes it is just "we have not got around to fixing it yet".

Less brutal: As per other responses, sometimes you MUST use it as there is no alternative. Other times it might be for backwards compatibility reasons. And framework code sometimes makes sense using it directly, because it is framework code. But if I had to guess without looking at code, many really should be fixed but it has not been high enough priority to do so yet.

Just remember the good parenting advice: "Kids, do what I say, not what I do!"

  • 6
    excellent quote:Kids, do what I say, not what I do! – sivakumar Jun 1 '16 at 1:16
  • That's not how it works kiddo – Ansyori Jun 1 '17 at 7:36
  • Is there a Magento 2 recommend way to have a soft dependency problem without object manager? I have a module with a soft dependency on another (it loads another class if the module exists). I can't DI that class in because then DI will fail. I can't even DI a Factory for that class because the factory will fail to DI. – Nathan Merrill Mar 14 at 14:54

Why is Magento doing what they recommend us not to do ? Does that mean there are some cases where we should use the ObjectManager directly ? If so, what those cases ?

Without knowing the full story here is my guess:

During the development of M2 the Magento team at some stage ran an automated script which replaced occurrences of Mage:getModel(), Mage::getSingleton(), $layout->createBlock(), etc. to use the ObjectManager.

Later refactoring should have fixed this to instead use proper dependency injection but there wasn't enough time / resources to convert all occurrences.

Also the Magento team lately seems to use this as an escape mechanism. Instead of breaking an existing implementation (by needing to change the constructor) they simply hide the new dependency via the ObjectManager. I can't say I agree with this approach - writing worse code to avoid a BC break.

What are the direct consequences of using the ObjectManager directly ?

I think your question already includes enough reasons. Generally it creates a hidden dependency, in other words the dependency is in the implementation details and not visible from the constructor alone.

  • It is ironic because had there done it properly before releasing to the public the BC wouldn't have been an issue at all – Robbie Averill May 31 '16 at 17:50

One very important reason that developers are strongly discouraged from using the Object Manager directly is that direct use causes the extension not to be installable in compiled release mode.

So it breaks for your customers using release mode, including all customers on Magento Cloud.

The Marketplace L1 scans do not currently test that extensions can be installed correctly: they are merely static scans.

This means that the responsibility for testing that your extension will install lies with you, the developer.

It seems like a reasonably large proportion of developers do not test their extensions to see if they can be installed, so do not run into the issues posed by incorrect ObjectManager usage.

[Edit: install tests were implemented in the Marketplace EQP tests in 2017, so if you use the object manager directly, you will likely cause those tests to fail. Your extension will then be rejected from the Marketplace until you resolve this.]

Should not use Object manager directly!

For instance:

\Magento\Framework\App\ObjectManager::getInstance();

also if you are working with event observers or plugins, you should never use it directly.

You could use it in Factories, but except that you should inject the Object Manager in the Constructor first then you can use its object in your method

Preferred to use:

1) declare private object:

private $_objectManager;

2) inject in the constructor and initialize:

public function __construct(
    \Magento\Framework\ObjectManagerInterface $objectmanager
) {
    $this->_objectManager = $objectmanager;
}

3) use in some method:

public function create() {
    return $this->_objectManager->create(/* ......... */);
}
  • Is it a good practice to use it this way? – enrico69 Sep 29 '17 at 16:04
  • Yes, because magento doesn't allow to use direct objectManager, so you have to use this way! – Ronak Chauhan Sep 29 '17 at 17:23
  • You should also never use it in events (I guess you mean Observers) and plugins. You should inject the objects that you need, not the ObjectManager. Only in a Factory you could use the ObjectManager and then you should indeed inject it instead of calling ::getInstance() – 7ochem Apr 10 at 13:38
  • Right, edit the answer @7ochem – Ronak Chauhan Apr 16 at 11:51
  • downvote any answer is not an appropriate way, If you have better knowledge then you can add your own answer or you can edit any other's answer to get better idea and helpful to others. @7ochem – Ronak Chauhan Apr 16 at 11:57

Your Answer

 
discard

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.