Close [x]

Dependency injection

Edit this page on GitHub

Dependency injection

Overview of dependency injection

The Magento software now uses dependency injection as an alternative to the Magento 1.x Mage class. Dependency injection means that all object dependencies are passed (that is, injected) into an object instead of being pulled by the object from the environment.

A dependency (sometimes referred to as coupling) implies the degree that one component relies on another component to perform a function. A large amount of dependency limits code reuse and makes moving components to new projects difficult.

In simple terms, if ModuleA needs to access some functionality in ModuleB, ModuleA depends on ModuleB. ModuleA consumes the service offered by ModuleB, so ModuleA is the consumer and ModuleB is the dependent.

In addition, we use dependency inversion, a coding principle that stipulates you use abstractions to reduce code dependencies. Dependency inversion means:

  • High-level modules should not depend on low-level modules. Both should depend on abstractions.
  • Abstractions should not depend upon details. Details should depend on abstractions.

For more information, see this article by Robert C. Martin.

The object manager specifies the dependency environment for constructor injection. The object manager must be present only when composing code. In larger applications, composing code is performed early in the bootstrapping process.

This topic uses the following terms:

Constructor injection

Type of dependency injection used for implementation dependencies (that is, dependencies that fulfill a business task of an object)

Factory

Object that creates the objects of a specific type. Unlike business objects, a factory can be dependent on the object manager.

Proxy

Auto-generated object that implements the same interface as the original object, but unlike this original object has only one dependency鈥攖he object manager. A proxy is used for lazy loading of optional dependencies. A proxy can be used to break cyclical dependencies. For more information about proxies, see Preview of constructor injection.

Lifecycle

An object鈥檚 lifecycle determines in what scope instances are reused, and when to release them.

Preview of constructor injection

Constructor injection must be used for all optional and required service dependencies of an object. Service dependencies fulfill business functions of your object.

<?php
class Test
{
    protected $class;
 
    public function __construct(SomeClass $class)
    {
        $this->class = $class;
    }
 
    public function execute()
    {
        //some code
 
        $this->class->execute();
 
        //some code
    }
}
 
$test->execute();
?>

Use a proxy for expensive optional dependencies; proxies are auto-generated, no coding is required.

A sample proxy (which you declare in di.xml) follows:

<type name="Magento\Backend\Model\Config\Structure\Element\Iterator\Field" shared="false">
    <arguments>
        <argument name="groupFlyweight" xsi:type="object">Magento\Backend\Model\Config\Structure\Element\Group\Proxy</argument>
    </arguments>
</type>

Configuration overview

The object manager needs the following configurations:

  • Class definitions for retrieving the types and numbers of class dependencies
  • Instance configurations for retrieving how the objects are instantiated and for defining their lifecycle
  • Abstraction-implementation mappings (that is, interface preferences) for defining what implementation is to be used upon request to an interface

To define the interface preferences for the object manager, use app/etc/di/*.xml, <your module dir>/etc/di.xml, and <your module dir>/etc/<areaname>/di.xml files depending on the scope it belongs in.

For example, to set the interface preferences for the Magento Admin, use app/code/core/Magento/Backend/etc/adminhtml/di.xml as follows:

You can also specify whether or not the object is shareable in its di.xml as follows:

Dependency injection is configuration-based; configurations are validated by config.xsd.

Object manager configurations can be specified at any of the following scopes:

  • Primary for bootstrapping (app/etc/di/*.xml)
  • Global across all of Magento (<your module directory>/etc/di.xml)
  • Area-specific configuration (<your module directory>/etc/<areaname>/di.xml)

    Area-specific means specific a Magento area (frontend, adminhtml, and so on). For example, here is the Magento Customer module鈥檚 adminhtml di.xml.

Each scope overrides any previously existing config when it is loaded.

Configurations for each scope are merged across modules, so there is no way to create a configuration that is only seen by a single module.

Class definitions

Magento uses class constructor signatures, not doc-block annotations, to retrieve information about class dependencies; that is, to define what dependencies are to be passed to an object.

Magento reads constructors using reflection. We recommend you use the single-store compiler tool or the multi-store compiler tool to pre-compile class definitions for better performance.

The parameters specified for a class type are inherited by its descendant classes.

Type configurations

By type, we mean basically the scope of the dependency (all of Magento, module, module area). For a review, see Configuration overview.

See one of the following sections for more information:

Specify types

Sample dependency injection by type:

The preceding sample declares the following types:

  • Magento\Core\Model\Session (if the type is not set explicitly, it is taken from the name)
  • config virtual type that extends Magento\Core\Model\Config
  • moduleConfig virtual type that extends type Magento\Core\Model\Config
  • Magento\Core\Model\App type. All instances of this type retrieve and instance of moduleConfig as a dependency

Arguments

Arguments are injected into a class instance during its creation. Argument names must correspond to constructor parameters of the configured class.

Sample argument that creates instances of Magento\Core\Model\Session with the argument $sessionName set to a value of adminhtml:

Argument definitions

The following tables discuss the meanings of argument definitions.

Object arguments
Node format Description Possible values

Object with default lifecycle

<argument xsi:type="object">
{Type_Name}</argument>

Object with specified lifecycle

<argument xsi:type="object"
shared="{shared}">{Type_Name}</argument>
Creates an instance of Type_Name type and passed as argument. Any class name, interface name, or virtual type name can be passed as Type_Name. shared defines the lifecycle of a created instance. n/a
String arguments
Node format Description Possible values

Regular string

<argument xsi:type="string">
{someValue}</argument>

Translated string

<argument xsi:type="string"
translate="true">{someValue}</argument>
someValue is passed as string. Any value is passed as a string.
Boolean arguments
Node format Description Possible values
<argument xsi:type="boolean">
{boolValue}</argument>
boolValue value is converted to bool Truth value discussed in the following table.
Truth value dictionary
Input type Input data Interpreted Boolean type
Boolean true true
Boolean false false
String "true" true
String "false" false
String "1" true
String "0" false
Integer 1 true
Integer 0 false

String literals are case-sensitive.

Number arguments
Node format Description Possible values
<argument xsi:type="number">
{numericValue}</argument>
numericValue as-is Integer, float, or numeric string.
Application arguments (that is, initialization parameters)
Node format Description Possible values
<argument xsi:type="init_parameter">
{Constant::NAME}</argument>
Global application argument represented by Constant::NAME looked up and passed as argument. Constant the containing name of a global argument.
Constant arguments
Node format Description Possible values
<argument xsi:type="const">
{Constant::NAME}</argument>
Constant::NAME passed as argument. Any constant name.
null
Node format Description Possible values
<argument xsi:type="null"/>
Pass null as argument. n/a
Array arguments
Node format Description Possible values
<argument xsi:type="array">
<item key="someItem"
xsi:type="string">someVal</item>
</argument>
Array with elements corresponding to the items passed as argument. Array can contain an infinite number of items. Each item can be any type as argument, including an array itself, or an object type. n/a
Sample:

When the configuration files for a given scope are merged, array arguments with the same name are merged into a new array. If a new configuration is loaded at a later time, either a more specific scope or through code, then any array definitions in the new configuration will completely replace the previously loaded config instead of being merged.

Parameter configuration inheritance

Parameters configured for a class type are automatically configured for all of its descendants. Any descendant can override parameters configured for the supertype (that is, the parent class or interface):

The preceding example configures all instances of Magento\Framework\View\Element\Context and its children to retrieve and instance of Magento\Framework\Url, but Magento\Backend\Block\Context overrides this and retrieves Magento\Backend\Model\Url.

Lifecycle management

An object鈥檚 lifecycle determines in what scope instances are reused, and when to release them.

The object manager creates objects and manages the lifecycle of the following types of objects:

  • singleton鈥擟reate one class instance at the first request and subsequently reuse that instance. Release the instance when the container with which it鈥檚 registered is disposed. This is the default.
  • transient鈥擟reate a new class instance every time the class is requested.

The preceding lifecycle can be configured as:

  • argument鈥擠efines the lifecycle for the argument only.
  • type鈥擜 convenience configuration that defines the lifecycle for all instances of the specified type.

Injectables and non-injectables

We use the following terms to describe objects that can or cannot be instantiated by the object manager:

Injectable

Object (typically a singleton) that can be instantiated by the object manager.

Non-injectable

Object that cannot be instantiated by the object manager. Typically, this object:

  • Has a transient lifecycle
  • Requires external input (such as data user input or data from database) to be properly created

Most models are non-injectable (for example, Magento\Catalog\Model\Product or Magento\User\Model\User).

You must observe the following rules:

  • Injectables can request other injectables in the constructor, but non-injectables cannot request other objects in a constructor
  • If a business function of an injectable object is to produce non-injectables, the injectable must ask for a factory in its constructor (due to the fact that factories are injectables)
  • If a business function of an injectable object is to perform some actions on a non-injectable, it must receive the non-injectable as a method argument

You can create non-injectables in services with object factories or you can pass them in as method parameters.

Do not push injectables to non-injectables because it violates the Law of Demeter and requires additional lookup during object unserialization.

Factories

Factories are special objects that have only one purpose: to create an instance of one non-injectable class or interface. Unlike other objects, factories are allowed to depend on the object manager. Factories are used to isolate object manager from business code:

<?php
class Magento\Core\Model\Config\BaseFactory
{
    protected $_objectManager;
 
    public function __construct(Magento\Framework\ObjectManager $objectManager)
    {
        $this->_objectManager = $objectManager;
    }
 
    public function create($sourceData = null)
    {
        return $this->_objectManager->create('Magento\Core\Model\Config\Base', array('sourceData' => $sourceData));
    }
} ?>

Most factories are simple, so developers do not have to bother with writing them. If a non-existent factory is encountered by object manager in runtime mode or compiler, the object manager generates the factory.

Compiler tool

To compile all non-existent proxies and factories; and to pre-compile class definitions, inheritance information, and plugin definitions for multiple stores or websites, see one of the following topics: