What is the difference between type and virtualType – Practical Example

When we started working with Magento2, we found lot of the new features and new concept with it. One of the major and confusing the topic of the Magento2 is difference between type and virtualType.

I am not going to give any definition or theoretical explanation of both so lets just start with practical example and create one module which explain the same.

So our module will be very basic and it’s namespace will be Codedecorator and name of the module Learning. Let’s start with adding required file for module.

<?php
\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'Codedecorator_Learning',
    __DIR__
);
<?xml version="1.0" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Codedecorator_Learning" setup_version="1.0.0" />
 </config>
<?php
namespace Codedecorator\Learning\Controller\Index;

use Magento\Framework\App\Action\Action;
use Magento\Framework\App\Action\Context;
use Magento\Framework\App\ResponseInterface;
use Codedecorator\Learning\Model\ClassDefault;

class Index extends Action
{
    protected $classDefault;

    public function __construct(
        Context $context,
        ClassDefault $classDefault
    )
    {
        $this->classDefault = $classDefault;
        parent::__construct($context);
    }

    public function execute()
    {
        echo "Index ClassA Namespace : ".$this->classDefault->namespace;
    }
}
<?php
namespace Codedecorator\Learning\Controller\Index;

use Magento\Framework\App\Action\Action;
use Magento\Framework\App\Action\Context;
use Magento\Framework\App\ResponseInterface;
use Codedecorator\Learning\Model\ClassDefault;

class Submit extends Action
{
    protected $classDefault;

    public function __construct(
        Context $context,
        ClassDefault $classDefault
    )
    {
        $this->classDefault = $classDefault;
        parent::__construct($context);
    }

    public function execute()
    {
        echo "Submit ClassA Namespace : ".$this->classDefault->namespace;
    }
}
<?php
namespace Codedecorator\Learning\Model;

class ClassDefault
{
    public $namespace;

    public function __construct($namespace = 'default')
    {
        $this->namespace = $namespace;
    }
}

So, we have added two controllers and one model file. Please check Model file carefully. We have one class property and it’s default value is “default”.

We are trying to use this ClassDefault.php file in one our controllers and trying to print the property of model class.

If try to call the controller by url then we will receive the “default” for the both controller. For example:

calling 1st controller
Calling 2nd controller

As you see in above screenshot property name is coming default in both the controller so lets try to change the ClassDefault property default value without modifying the class directly and do so we can just need to add di.xml

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">

    <!-- Changing value for both Controllers  -->
   <type name="Codedecorator\Learning\Model\ClassDefault">
        <arguments>
                <argument name="namespace" xsi:type="string">test</argument>
        </arguments>
    </type>
 
</config>

As you noticed that we have used the type node and we have changed the namspace property from the default to test. Let’s flush cache as we have changed in the XML file and check the result.

Type node result.
Type node result

Yes, result changed and it is showing test instead of the default for both the controller.

I guess now you understand concept of type that it will change the property value for all the controller which is using the DefaultClass.php

If we want to change the property value for the Index.php controller and not for the Submit.php controller so here virtualType node comes in picture. It will allow us to create subclass and use that class wherever required. If you still have confusion check the updated di.xml and see the result.

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">

    <virtualType name="ClassDefaultVirtual" type="Codedecorator\Learning\Model\ClassDefault">
        <arguments>
            <argument name="namespace" xsi:type="string">test</argument>
        </arguments>
    </virtualType>

    <type name="Codedecorator\Learning\Controller\Index\Index">
        <arguments>
            <argument name="classDefault" xsi:type="object">ClassDefaultVirtual</argument>
        </arguments>
    </type>
</config>

You should flush the cache after making anything changes in XML files. Here is the result:

Result changed for the index controller
Default value came as it does not affect the submit controller

I hope this example makes helps you to understand the difference between the type and virtual type. Please leave a comment if you have any doubt.

Leave a Reply

Your email address will not be published. Required fields are marked *