4

Recently I came across a situation in magento where settings for instance object were remaining persistent and it made we wonder how magento's di is working.

I created a module that injects magento's curl class \Magento\Framework\HTTP\Adapter\Curl

public function __construct
(
  \Magento\Framework\HTTP\Adapter\Curl $curl
)
{
  $this->curl = $curl;
}

public function getGeoIpResponse($ip)
{
  $this->curl->setConfig(['header' => false]);
  $this->curl->write('GET', $ip);

  return $this->curl->read();
}

This provides back a json with no header, because of ['header' => false], prepended to the response.

Now in a separate class I inject the same curl class and run a similar method but DO NOT set the header to false. However the response comes back with no header; the default config returns a header. In order to receive a header i would have to set ['header' => true] in the config.

public function __construct
(
  \Magento\Framework\HTTP\Adapter\Curl $curl
)
{
  $this->curl = $curl;
}

public function getFixerResponse($base) {

  $this->curl->write('GET', $this->fixerUrl . $base);

  $response = $this->curl->read();

  return $response;
}

If I remove the first instance where ['header' => false], leaving the second instance unchanged, then the second instance's response returns a header.

I expected the instances to work independent of each other but it seems the config is shared between the two objects.

Can anyone explain why the configuration of the first instance is remaining persistent on the second?

3

When a class is requested as a dependency for an other class Magento will first check in the DI container (DIC) for an instance of that class.
If it exists, it will return it, if not it will create the instance, add it to the DIC and return it to be injected in the class that requires it.
This means that all dependencies act as singletons.
In you case, if you need a different instance of the Curl class you can just inject a CurlFactory instance instead of the Curl instance.
Something like this:

First class

public function __construct
(
  \Magento\Framework\HTTP\Adapter\CurlFactory $curlFactory //don't worry, the Factory class will be autogenerated
)
{
  $this->curl = $curlFactory->create();
}

public function getGeoIpResponse($ip)
{
  $this->curl->setConfig(['header' => false]);
  $this->curl->write('GET', $ip);

  return $this->curl->read();
}

Second class

public function __construct
(
  \Magento\Framework\HTTP\Adapter\CurlFactory $curlFactory //don't worry, the factory class will be auto generated
)
{
  $this->curl = $curlFactory->create();
}

public function getFixerResponse($base) {

  $this->curl->write('GET', $this->fixerUrl . $base);

  $response = $this->curl->read();

  return $response;
}
| improve this answer | |
  • In this case CurlFactory already exists. After using CurlFactory, instances worked independently. – Xenocide8998 Jun 28 '16 at 14:02
2

By default, the object instance is shared. If you request the same object many times in different classes you will get the same instance.

See http://devdocs.magento.com/guides/v2.0/extension-dev-guide/depend-inj.html#object-manager-overview#object-lifestyle-management for more details

| improve this answer | |
0

Earlier, I had the same issue with my code.Magento 2 class has some limitation that we can not use more than 13 instances of another class within your class body. You can use less than 13 instances or create another class and define the maximum object in that call and use new class (has initialised objects) into your class.

| improve this answer | |
0

It is about prototype vs singleton scope.

In magento2, by default, the object instance is unique (shared) during the container's lifecycle - each injection returns the same instance (singleton scope).

To change it to a prototype scope, change your di.xml file and use shared="false":

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

If shared is set to false, then Magento2 will use the create method to instantiate an object every time it sees your class (instead of the default get method)

http://alanstorm.com/magento_2_object_manager_instance_objects

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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