41

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">
  • 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 Aug 21 '14 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. – David Manners Aug 21 '14 at 14:36
84

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

  • Thanks a lot @Chris finally some logical justification i found – Suman-PHP4U Aug 11 '17 at 12:11
  • That was simple and the best demonstration. – Umar Jan 1 at 14:56
  • This answer is better then Magento official doc – Suman-PHP4U Mar 17 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 May 9 at 2:47
21

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/

10

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.

  • 1
    you missed the quotes around the word fun ;) – David Manners Aug 21 '14 at 15:06
  • 1
    @DavidManners. Right. I fixed it. :) – Marius Aug 21 '14 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). – Chris O'Toole Aug 22 '14 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. – Chris O'Toole Aug 22 '14 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 – Chris O'Toole Aug 22 '14 at 19:48

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.