60

In the di.xml that comes with Magento2 there is a node type and a node virtualType. My questions is what is this virtualType and in what case should it be used instead of type?

In some places it looks like a symbolic link or rewrite:

<virtualType name="Magento\Core\Model\Session\Storage" type="Magento\Framework\Session\Storage">

Where one full path gets changed into another but in other places it appears to be used as a way to define a shorter alias.

<virtualType name="lessFileSourceBase" type="Magento\Framework\View\File\Collector\Base">
2
  • 3
    I have no idea (yet) what they even mean but you can start digging from here: Magento\Framework\ObjectManager\Config\Mapper\Dom::convert. There is a switch statement in there somewhere.
    – Marius
    Commented Aug 21, 2014 at 14:34
  • Thanks @Marius, I am also wondering if lessFileSourceBase is limited to the xml or if that can also be used outside. Guess I better get digging. Commented Aug 21, 2014 at 14:36

3 Answers 3

126

Virtual types are a way to inject different dependencies into existing classes without affecting other classes.

For example, the Magento\Framework\Session\Storage class takes a $namespace argument in its constructor, which defaults to the value 'default', and you could use the type definition to change the namespace to 'core'.

<type name="Magento\Framework\Session\Storage">
    <arguments>
        <argument name="namespace" xsi:type="string">core</argument>
    </arguments>
</type>

The above config would make it so that all instances of Magento\Framework\Session\Storage have a namespace of 'core'. Using a virtual type allows for the equivalent of a sub-class to be created, where only the sub-class has the altered argument values.

In the codebase we see the following two configurations:

<virtualType name="Magento\Core\Model\Session\Storage" type="Magento\Framework\Session\Storage">
    <arguments>
        <argument name="namespace" xsi:type="string">core</argument>
    </arguments>
</virtualType>

<type name="Magento\Framework\Session\Generic">
    <arguments>
        <argument name="storage" xsi:type="object">Magento\Core\Model\Session\Storage</argument>
    </arguments>
</type>

The first snippet creates a virtual type for Magento\Core\Model\Session\Storage which alters the namespace, and the second inject the virtual type into Magento\Framework\Session\Generic. This allows Magento\Framework\Session\Generic to be customized without affecting other classes that also declare a dependency on Magento\Framework\Session\Storage

7
  • Thanks a lot @Chris finally some logical justification i found Commented Aug 11, 2017 at 12:11
  • That was simple and the best demonstration.
    – CodeGenius
    Commented Jan 1, 2019 at 14:56
  • 3
    This answer is better then Magento official doc Commented Mar 17, 2019 at 7:08
  • <type> is using a virtual class which doesn't actually exist. This way the argument modification in virtualType will take effect only when the class using the virtualType is initialized which is Magento\Framework\Session\Generic in the example
    – Arif Ahmad
    Commented May 9, 2019 at 2:47
  • I found an example that can help us to undestand more deeply magently.com/blog/… Commented Jan 12, 2022 at 11:54
35

Another way to understand virtual types -

Let's say that you have a class \Class1, which has the following constructor -

public function __construct(\Class2 $argOfClass1){...}

And \Class2 has the following constructor -

public function __construct(\Class3 $argOfClass2){...}

Now, you want to change the type of $argOfClass2 from \Class3 to \Class4, but only when \Class2 is used as $argOfClass1.

The "old" way to do that would be to add the following in di.xml -

<type name="Class1">
    <arguments>
         <argument name="argOfClass1" xsi:type="object">Class5</argument>
    </arguments>
</type>

where \Class5 is the following:

class \Class5 extends \Class2{
    public function __construct(\Class4 $argOfClass2){...}
}
   

Instead of using this way, you can use the virtual types to accomplish the same, by adding the following to di.xml:

<virtualType name="Class5" type="Class2">
    <arguments>
        <argument name="argOfClass2" xsi:type="string">Class4</argument>
    </arguments>
</virtualType>

<type name="Class1">
    <arguments>
         <argument name="argOfClass1" xsi:type="object">Class5</argument>
    </arguments>
</type>
   

As you can see, using the virtual type saved you the work of creation of Class5.

For further reference I suggest to read Alan Storm's article regarding virtual types in Magento2 - http://alanstorm.com/magento_2_object_manager_virtual_types/

Practical way using magento2 module

3
  • 1
    good expalination , Commented Mar 12, 2019 at 7:12
  • Easy to understand. Thanks for sharing such a basic example. Commented Jul 30, 2019 at 10:50
  • "As you can see, using the virtual type saved you the work of creation of Class5" - Grasping this concept helped me understand the purpose of Virtual Types. Thanks for making this more clear for me! Commented Jan 10, 2022 at 17:09
11

In the same di.xml file I found that lessFileSourceBase is passed as an argument for lessFileSourceBaseFiltered that is passed as an argument for lessFileSourceBaseSorted that is passed as an argument for type Magento\Framework\Less\File\Collector\Aggregated.

I found no other occurrence of lessFileSourceBase (or lessFileSource ) in an other file except di.xml from the core module. Only in some cache files but those are not important.

I guess if you are not going to use the virtual type in a PHP class, but only in the di xml files then you are not required to make it look like a class name and you can use an alias.

But this is just pure speculation.
It will be "fun" to try to create a class and inject in its constructor an instance of lessFileSourceBase to see how it behaves.

6
  • 2
    you missed the quotes around the word fun ;) Commented Aug 21, 2014 at 15:06
  • 1
    @DavidManners. Right. I fixed it. :)
    – Marius
    Commented Aug 21, 2014 at 15:08
  • @Marius: If you alter \Magento\Framework\Session\Generic source file to depend on Magento\Core\Model\Session\Storage instead of StorageInterface you should get a 'Class Magento\Core\Model\Session\Storage does not exist' exception. The reason being that ObjectManager doesn't create an instance of the virtualType, but just uses that to determine what arguments to provide for the constructor of the concrete type that is referenced by the virtualType definition (Magento\Framework\Session\Storage for the above example). Commented Aug 22, 2014 at 19:43
  • Can see this in the Factory, where $requestedType represents the virtual type and is used to gather arguments, but $type is the concrete type that the virtualType maps to and is used for the object instantiation call. Commented Aug 22, 2014 at 19:46
  • So even if lessFileSourceBase was in a more namespace\class type style, it wouldn't allow for direct reference by another php class, just for injection via the di.xml Commented Aug 22, 2014 at 19:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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