di.xml Structure and Scopes
The di.xml file is the primary configuration for dependency injection in Magento 2.
Global vs area-specific:
etc/di.xml # Global (all areas)
etc/frontend/di.xml # Frontend only
etc/adminhtml/di.xml # Admin only
etc/webapi_rest/di.xml # REST API only
etc/webapi_graphql/di.xml # GraphQL only
etc/crontab/di.xml # Cron only
Merge behavior:
- Global di.xml loads first
- Area-specific di.xml loads second
- Area-specific takes precedence for same keys
Basic di.xml structure:
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<!-- Preferences -->
<preference for="Interface" type="Implementation"/>
<!-- Type configuration -->
<type name="ClassName">
<arguments>
<argument name="param" xsi:type="string">value</argument>
</arguments>
<plugin name="name" type="PluginClass"/>
</type>
<!-- Virtual types -->
<virtualType name="Alias" type="RealClass"/>
</config>
di.xml location per module:
app/code/Vendor/Module/
├── etc/
│ ├── di.xml # Global
│ ├── frontend/
│ │ └── di.xml # Frontend
│ ├── adminhtml/
│ │ └── di.xml # Admin
│ └── webapi_rest/
│ └── di.xml # REST API
Type Configuration and Arguments
The <type> element configures constructor arguments, plugins, and other settings for specific classes.
Type configuration:
<type name="Vendor\Module\Service\Processor">
<arguments>
<argument name="batchSize" xsi:type="number">100</argument>
<argument name="timeout" xsi:type="number">30</argument>
<argument name="enabled" xsi:type="boolean">true</argument>
<argument name="apiKey" xsi:type="string">abc123</argument>
<argument name="logger" xsi:type="object">Vendor\Module\Logger\CustomLogger</argument>
<argument name="config" xsi:type="array">
<item name="retry_count" xsi:type="number">3</item>
<item name="mode" xsi:type="string">strict</item>
</argument>
<argument name="modes" xsi:type="array">
<item name="0" xsi:type="string">active</item>
<item name="1" xsi:type="string">inactive</item>
</argument>
</arguments>
</type>
Argument types:
<!-- String -->
<argument name="name" xsi:type="string">value</argument>
<!-- Number (int/float) -->
<argument name="count" xsi:type="number">42</argument>
<!-- Boolean -->
<argument name="flag" xsi:type="boolean">true</argument>
<!-- Object (class/interface) -->
<argument name="dep" xsi:type="object">Some\Class</argument>
<!-- Array -->
<argument name="items" xsi:type="array">
<item name="key" xsi:type="string">value</item>
</argument>
<!-- Constant -->
<argument name="mode" xsi:type="const">Some\Class::CONSTANT</argument>
Extending existing type configuration:
<!-- Add argument to existing class -->
<type name="Magento\Catalog\Model\Product">
<arguments>
<argument name="customAttribute" xsi:type="string">value</argument>
</arguments>
</type>
Virtual Types
Virtual types create named configurations of existing classes without creating new PHP classes.
Basic virtual type:
<virtualType name="LoggerForImport" type="Magento\Framework\Logger\Monolog">
<arguments>
<argument name="name" xsi:type="string">import.log</argument>
</arguments>
</virtualType>
Virtual type with arguments:
<virtualType name="CustomLogger" type="Vendor\Module\Logger\Logger">
<arguments>
<argument name="logFile" xsi:type="string">custom.log</argument>
<argument name="level" xsi:type="string">debug</argument>
<argument name="handlers" xsi:type="array">
<item name="stream" xsi:type="object">
Magento\Framework\Logger\Handler\Stream
</item>
</argument>
</arguments>
</virtualType>
Using virtual type as dependency:
<!-- Virtual type defined -->
<virtualType name="OrderLogger" type="Vendor\Module\Logger\FileLogger">
<arguments>
<argument name="filename" xsi:type="string">orders.log</argument>
</arguments>
</virtualType>
<!-- Inject virtual type into class -->
<type name="Vendor\Module\Service\OrderService">
<arguments>
<argument name="logger" xsi:type="object">OrderLogger</argument>
</arguments>
</type>
Virtual type benefits:
- No new PHP classes needed
- Different configurations of same class
- No preference conflicts
- Can override any class configuration
- Easy to test with different configurations
Plugin Declarations
Plugins (interceptors) are declared in di.xml to modify class method behavior.
Basic plugin declaration:
<type name="Magento\Catalog\Model\ProductRepository">
<plugin name="vendor_product_after_save"
type="Vendor\Module\Plugin\ProductAfterSave"
sortOrder="10"/>
</type>
Plugin attributes:
name- Unique identifier across all plugins for this classtype- Plugin class implementing before/after/around methodssortOrder- Execution order (lower = first)disabled- Set totrueto disableshared- Whether plugin instance is shared (default: false)
Multiple plugins:
<type name="Magento\Catalog\Model\ProductRepository">
<plugin name="first_plugin" type="...\FirstPlugin" sortOrder="10"/>
<plugin name="second_plugin" type="...\SecondPlugin" sortOrder="20"/>
<plugin name="third_plugin" type="...\ThirdPlugin" sortOrder="30"/>
</type>
Plugin execution order:
around(10) → before(10) → before(20) → Method → after(20) → after(10)
Disabling plugins:
<type name="Magento\Catalog\Model\ProductRepository">
<plugin name="vendor_product_after_save" disabled="true"/>
</type>
Plugin class example:
<?php
namespace Vendor\Module\Plugin;
class ProductAfterSave
{
public function beforeSave($subject, $product)
{
// Before plugin
return [$product];
}
public function afterSave($subject, $result)
{
// After plugin
return $result;
}
public function aroundSave($subject, $proceed, $product)
{
// Around plugin
$result = $proceed($product);
return $result;
}
}
Quiz
1. What takes precedence when merging global and area-specific di.xml?
2. What xsi:type is used for class/object arguments?
3. How do you disable a plugin in di.xml?
Flashcards
Question
What are the five di.xml scopes?
Click to reveal answer
Answer
global, frontend, adminhtml, webapi_rest, webapi_graphql, crontab
Question
What xsi:type creates a configured variant of a class?
Click to reveal answer
Answer
virtualType
Question
How do you create a new instance instead of shared?
Click to reveal answer
Answer
Set shared="false" on the type element
Question
What element declares plugins in di.xml?
Click to reveal answer
Answer
<plugin> inside a <type> element
Revision Notes
Key Takeaways
- 1. di.xml exists in global and area-specific scopes
- 2. Area-specific takes precedence over global
- 3. Type configures constructor arguments and plugins
- 4. Virtual types create configured variants without new classes
- 5. Plugin sortOrder controls execution order
- 6. Arguments support string, number, boolean, object, array, const
Interview Tips
- • Explain the difference between global and area-specific di.xml
- • Describe how virtual types work with examples
- • Discuss plugin declaration and ordering
- • Know all argument types in di.xml
- • Explain when to use type vs virtual type vs preference
Cheat Sheet
di.xml Cheat Sheet
Scopes: global, frontend, adminhtml, webapi_rest, webapi_graphql, crontab
Elements:
<preference for="Interface" type="Implementation"/>
<type name="Class">
<arguments>
<argument name="param" xsi:type="string">value</argument>
</arguments>
<plugin name="name" type="Plugin" sortOrder="10"/>
</type>
<virtualType name="Alias" type="Class"/>
Argument Types:
string, number, boolean, object, array, const
Plugin Order:
around(10) → before(10) → Method → after(10)