Magento 2 Object Manager: Instance Objects

It’s been a long and winding road, but the end is in sight! In this, the penultimate article in our object manager tutorial, we’re going to discuss working with instance and non-injectable objects in Magento 2.

This article assumes a basic familiarity with Magento 2 concepts, and may brush past something complicated. If you’re confused you may want to start from the beginning, or use the comment system below to point to your Magento Stack Exchange question.

Let’s get to it!

Sample Code

We’ve prepared a small sample Magento 2 module that we’ll reference and use in this article. You can download the module If you’re not familiar with manually installing Magento 2 modules the first article in this series.

To test that you’ve installed the module correctly, try running the following command

$ php bin/magento ecommage:tutorial-instance-objects
You've installed Ecommage_TutorialInstanceObjects!
If you see the You've installed Ecommage_TutorialInstanceObjects! message, you’re all set.

Shared/Unshared, Singleton/Instance

Back in our first article, we introduced two object manager methods for instantiating objects

$object  = $manager->create('Ecommage\TutorialInstanceObjects\Model\Example');
$object  = $manager->get('Ecommage\TutorialInstanceObjects\Model\Example');

The create method will instantiate a new object each time it’s called. The get method will instantiate an object once, and then future calls to get will return the same object. This behavior is similar to Magento 1’s getModel vs.getSingleton factories

Mage::getModel('group/class');      // ->create, or instance object
Mage::getSingleton('group/class');  // ->get,    or instance object

What we didn’t cover was how the automatic constructor dependency injection system decides which method to use when it encounters a constructor parameter. Consider a constructor that looks like this.

use Ecommage\TutorialInstanceObjects\Model\Example;
public function __construct(Example $example)
    //is $example created with `get` or `create`?
    $this->example = $example?

We know the parameter will be a Ecommage\TutorialInstanceObjects\Model\Example object, but we don’t know if it will be a new instance of a Ecommage\TutorialInstanceObjects\Model\Exampleobject, or the same Ecommage\TutorialInstanceObjects\Model\Example object passed/injected into other constructors.

By default, all objects created via automatic constructor dependency injection are “singleton-ish” objects — i.e. they’re created via the object manager’s get method.

If you want a new instance of an object, i.e. you want the object manager to use create, you’ll need to add some additional <type/> configuration to your module’s di.xml file.

If we wanted the object manager to instantiate Ecommage\TutorialInstanceObjects\Model\Example as an instance object every time, we’d add the following configuration to our di.xml

    <!-- ... -->
    <type name="Ecommage\TutorialInstanceObjects\Model\Example" shared="false">
        <!-- ... arguments/argument tags here if you want to change injected arguments -->

This is the same <type/> tag we saw back in our argument replacement tutorial. The name attribute should be the name of the class whose behavior you want to change.

The new-to-us attribute is shared. If shared is set to false, then Magento 2 will use the create method to instantiate an object every time it encounters Ecommage\TutorialObjectManager1\Model\Example as an automatically injected constructor argument. The shared attribute has no effect on objects instantiated directly via PHP’s new keyword, or the object manager’s two methods.

This attribute is named shared due to an implementation detail in the object manager. When you use get to instantiate an object, the object manager stores all the already instantiated objects in a _sharedInstances array.


public function get($type)
    $type = ltrim($type, '\\');
    $type = $this->_config->getPreference($type);
    if (!isset($this->_sharedInstances[$type])) {
        $this->_sharedInstances[$type] = $this->_factory->create($type);
    return $this->_sharedInstances[$type];

When you configure a specific type (i.e. a specific PHP class) with shared="false", you’re telling Magento 2 that you don’t want to use this _sharedInstances array.

So, all you need to remember here is shared="true" is the default, and you’ll get a singleton-ish/global object. If you change your type configuration to shared="false", the automatic constructor dependency injection system will start instantiating a new parameter every-time a programmer instantiates the attribute’s owner object.

Magento 2 Factories

While the shared attribute is a useful bit of duct tape for those times you need an injected dependency to be a brand new instance object, it’s not an ideal solution for every (or even most) cases where you don’t want singletons.

One problem with shared is the injected dependency is still dependent on its owner object being shared or un-shared. There’s lots of times where you just need a new instance of an object and might not be able to refactor your object relationships to accomplish that.

A perfect example of this are CRUD data objects, such as Magento’s CMS page objects or the catalog product objects. In Magento 1 you’d create a CMS page object like this 


In Magento 2, these sorts of objects are called “non-injectables”. Dependency injection is meant for objects that “do some thing”, or “provide some service”. These data objects, however, are meant to “identify this specific thing”. What we’re going to look at next is how to use these sorts of objects without automatic constructor dependency injection tying our hands.

First, there’s nothing stopping you from directly instantiating an object via PHP’s new method

$product = new \Magento\Cms\Model\Page;

However, if you were to do this, your CMS Page object loses out on all of Magento’s object manager features.

Fortunately, the Magento 2 core developers haven’t abandoned us. In Magento 2, you instantiate these sorts of non-injectable objects via factory objects. Like so much in Magento 2, an example is worth 1,000 words.


public function __construct(
    \Magento\Cms\Model\PageFactory $pageFactory =
    $this->pageFactory = $pageFactory;
    return parent::__construct();
public function execute(InputInterface $input, OutputInterface $output)
    $page = $this->pageFactory->create();
    foreach($page->getCollection() as $item)
        $output->writeln($item->getId() . '::' . $item->getTitle());
    $page = $this->pageFactory->create()->load(1);       

Here’s what’s going on: In the __constructor method, the command uses Magento’s automatic constructor dependency injection to create a Magento\Cms\Model\PageFactory object, and then (per Magento convention) assigns that object to the pageFactory property.

public function __construct(
    \Magento\Cms\Model\PageFactory $pageFactory =
    $this->pageFactory = $pageFactory;

Then, in execute, we use this factory object to create a CMS page object (using the factory’s create method)

$page = $this->pageFactory->create();

In Magento 1, the above is roughly equivalent to

In Magento 1, we had a set of factory methods (getModel, ‘helper’, ‘createBlock’). In Magento 2 — every non-injectable object has its own factory object.

You can find the factory for any model class by appending the text Factory to that model class’s name. Above we wanted to instantiate Magento\Cms\Model\Page objects, so the factory class was

Object we Want: Magento\Cms\Model\Page
Factory to Use: Magento\Cms\Model\PageFactory

Similarly, here’s the two classes for a product object

Object we Want: Magento\Catalog\Model\Product         
Factory to Use: Magento\Catalog\Model\ProductFactory

Once we use a factory to instantiate a class, we have most (if not all) of our old Magento 1 CRUD methods available to us (loadgetDatagetCollection, etc.)

$page = $this->pageFactory->create();
foreach($page->getCollection() as $item)
    $this->output($item->getId() . '::' . $item->getTitle());
$page = $this->pageFactory->create()->load(1);

This may take a little getting used to, but compared to the error prone XML configuration needed to use Magento 1’s factory methods, this is already a big win.

Factory Definitions and Code Generation

There’s one last thing to cover about factory objects in Magento 2 that might answer a few questions in your head

  • Ugh! I need to define a bunch of boiler plate factory code? Lame.
  • Where can I see what a factory object looks like?

If we start with the second and more adult question, you may be in for a small surprise. Based on the factory’s full class name, (Magento\Cms\Model\PageFactory), you might expect to find it at one of the following locations


However, neither of these files exist.

That’s because Magento 2 uses automatic code generation to create factory classes. You may remember this code generation from the proxy object article. If you’ve actually run the code above, you’ll find the PageFactory class in the following location.


While the specifics are beyond the scope of this article, whenever

  • PHP encounters a class name that ends in Factory
  • And the autoloader can’t load that class because there’s no definition file

Magento 2 will automatically create the factory.

If you’re curious how this happens this Stack Exchange answer showing the Magento/Framework/Code/Generator/Autoloader kickoff point is a good place to start.

Factories for All

Factories aren’t just for Magento core code — they’ll work with any module class. The sample module we had you install includes a Ecommage\TutorialInstanceObjects\Model\Example object. Let’s replace the__construct method with one that adds a factory class for the Example object.

use Ecommage\TutorialInstanceObjects\Model\ExampleFactory;
class RunCommand extends Command
    protected $exampleFactory;
    public function __construct(ExampleFactory $example)
        $this->exampleFactory = $example;
        return parent::__construct();

Then, we’ll use that factory in execute.

protected function execute(InputInterface $input, OutputInterface $output)
    $example = $this->exampleFactory->create();
        "You just used a"                . "\n\n    "
        get_class($this->exampleFactory) . "\n\n" .
        "to create a \n\n    "           .
        get_class($example) . "\n");

Run our command with the above execute method in place, and you should see the following. 

$ php bin/magento ecommage:tutorial-instance-objects
You just used a
to create a

As you can see, this code ran without issue, despite our never defining aEcommage\TutorialInstanceObjects\Model\ExampleFactory class. You can find the factory definition in the generated code folder


 * Factory class for @see \Ecommage\TutorialInstanceObjects\Model\Example
class ExampleFactory
    protected $_objectManager = null;
    protected $_instanceName = null;
    public function __construct(
        \Magento\Framework\ObjectManagerInterface $objectManager,
        $instanceName = '\\Ecommage\\TutorialInstanceObjects\\Model\\Example'
        $this->_objectManager = $objectManager;
        $this->_instanceName = $instanceName;
    public function create(array $data = array())
        return $this->_objectManager->create($this->_instanceName, $data);

As for the specific implementation — right now a factory’s create method accepts an array of parameters and users the object manager to create the object. However, future versions of Magento may change how these factories work. By having the framework generate these factories Magento 2 saves us the error prone busy work of coding up this boilerplate and the core team maintains control over how the factories work.

Wrap Up

With this article and its six predecessors complete, we have a pretty good understanding of Magento’s object system, how that system impacts the shape of the Magento code base, and (most importantly) the basic understanding that’s critical if we want to apply reason to Magento 2 code in the real world.

There is, however, one last thing we need to cover, and that’s the object plugin system. The plugin system is the true successor to Magento 1’s class rewrite system, and with a solid understanding of the object manager and automatic constructor dependency injection, we’re ready to tackle this next time in our final Object Manager tutorial.


There is no comment on this post. Be the first one.

Leave a comment