String and Number Arguments
The simplest arguments in di.xml are scalar values—strings and numbers. These pass literal configuration values into constructor parameters.
String arguments:
<type name="Vendor\Module\Service\Logger">
<arguments>
<argument name="logFile" xsi:type="string">var/log/custom.log</argument>
<argument name="channel" xsi:type="string">vendor_module</argument>
</arguments>
</type>
Number arguments:
<type name="Vendor\Module\Service\Processor">
<arguments>
<argument name="batchSize" xsi:type="number">100</argument>
<argument name="timeout" xsi:type="number">30.5</argument>
</arguments>
</type>
How values resolve:
xsi:type="string"→ PHPstringxsi:type="number"→ PHPintorfloat(Magento determines automatically)- The constructor parameter type hint must accept the value
Practical example:
namespace Vendor\Module\Service;
class Processor
{
public function __construct(
private int $batchSize,
private string $logFile
) {}
}
<type name="Vendor\Module\Service\Processor">
<arguments>
<argument name="batchSize" xsi:type="number">50</argument>
<argument name="logFile" xsi:type="string">import.log</argument>
</arguments>
</type>
Important: If no argument is configured in di.xml and no default value exists, the ObjectManager will attempt to resolve the dependency using type inference. Scalar types (string, int, float, bool) cannot be auto-resolved, so they must be explicitly configured or have default values.
Boolean and Null Arguments
Boolean and null arguments control feature flags and optional dependencies.
Boolean arguments:
<type name="Vendor\Module\Service\Exporter">
<arguments>
<argument name="debugMode" xsi:type="boolean">true</argument>
<argument name="enableCompression" xsi:type="boolean">false</argument>
</arguments>
</type>
Null arguments:
<type name="Vendor\Module\Service\Handler">
<arguments>
<argument name="fallbackHandler" xsi:type="object">null</argument>
</arguments>
</type>
Null for optional dependencies:
namespace Vendor\Module\Service;
class Handler
{
public function __construct(
private \Psr\Log\LoggerInterface $logger,
private ?\Vendor\Module\Handler\FallbackHandler $fallbackHandler = null
) {}
public function handle(string $data): void
{
if ($this->fallbackHandler !== null) {
$this->fallbackHandler->process($data);
}
}
}
When to use null:
- Making an object dependency optional
- Disabling a feature that normally requires an object
- Overriding a preference to remove a dependency
Boolean use cases:
- Feature flags within DI configuration
- Toggling behaviors based on scope (frontend vs admin)
- Conditional logic in constructor setup
Object Arguments
Object arguments inject specific class implementations or interface bindings into constructor parameters.
Basic object argument:
<type name="Vendor\Module\Service\NotificationService">
<arguments>
<argument name="sender" xsi:type="object">Vendor\Module\Email\SmtpSender</argument>
</arguments>
</type>
Interface binding:
<type name="Vendor\Module\Service\NotificationService">
<arguments>
<argument name="sender" xsi:type="object">Vendor\Module\Email\SmsSender</argument>
</arguments>
</type>
// Constructor expects interface
public function __construct(
private \Vendor\Module\Email\SenderInterface $sender
) {}
Virtual type as argument:
<virtualType name="FileLogger" type="Magento\Framework\Logger\Monolog">
<arguments>
<argument name="name" xsi:type="string">custom.log</argument>
</arguments>
</virtualType>
<type name="Vendor\Module\Service\Processor">
<arguments>
<argument name="logger" xsi:type="object">FileLogger</argument>
</arguments>
</type>
Multiple objects in array:
<type name="Vendor\Module\Service\ChainProcessor">
<arguments>
<argument name="processors" xsi:type="array">
<item name="0" xsi:type="object">Vendor\Module\Processor\Validation</item>
<item name="1" xsi:type="object">Vendor\Module\Processor\Transformation</item>
<item name="2" xsi:type="object">Vendor\Module\Processor\Export</item>
</argument>
</arguments>
</type>
Important notes:
- Object arguments must reference valid PHP classes or interfaces
- The ObjectManager creates instances automatically
- Shared objects are reused; non-shared create new instances per injection
Array, Const, and Complex Arguments
Array and const arguments handle structured configuration data.
Array arguments:
<type name="Vendor\Module\Service\ConfigurableProcessor">
<arguments>
<argument name="options" xsi:type="array">
<item name="retry_count" xsi:type="number">3</item>
<item name="retry_delay" xsi:type="number">5</item>
<item name="mode" xsi:type="string">strict</item>
<item name="fallback_strategy" xsi:type="string">skip</item>
</argument>
<argument name="allowed_types" xsi:type="array">
<item name="0" xsi:type="string">simple</item>
<item name="1" xsi:type="string">configurable</item>
<item name="2" xsi:type="string">bundle</item>
</argument>
</arguments>
</type>
Const arguments:
<type name="Vendor\Module\Service\Logger">
<arguments>
<argument name="logLevel" xsi:type="const">Psr\Log\LogLevel::ERROR</argument>
<argument name="maxFileSize" xsi:type="const">Vendor\Module\Config\Constants::MAX_LOG_SIZE</argument>
</arguments>
</type>
Nested arrays:
<argument name="handlers" xsi:type="array">
<item name="stream" xsi:type="array">
<item name="type" xsi:type="string">stream</item>
<item name="level" xsi:type="number">100</item>
<item name="bubble" xsi:type="boolean">false</item>
</item>
<item name="rotating" xsi:type="array">
<item name="type" xsi:type="string">rotating</item>
<item name="max_files" xsi:type="number">30</item>
</item>
</argument>
Merging arrays across scopes:
<!-- etc/di.xml (global) -->
<type name="Vendor\Module\Service\Processor">
<arguments>
<argument name="modes" xsi:type="array">
<item name="0" xsi:type="string">default</item>
</argument>
</arguments>
</type>
<!-- etc/frontend/di.xml (frontend) -->
<type name="Vendor\Module\Service\Processor">
<arguments>
<argument name="modes" xsi:type="array">
<item name="1" xsi:type="string">frontend_only</item>
</argument>
</arguments>
</type>
Array arguments are merged by key. Numeric keys are re-indexed.
Argument Overriding and Scope Precedence
Arguments can be overridden at different scopes, with area-specific configurations taking precedence.
Scope precedence order:
- webapi_rest/di.xml
- webapi_graphql/di.xml
- adminhtml/di.xml
- frontend/di.xml
- crontab/di.xml
- etc/di.xml (global)
Overriding example:
<!-- etc/di.xml (global) -->
<type name="Vendor\Module\Service\Logger">
<arguments>
<argument name="logLevel" xsi:type="string">info</argument>
<argument name="logFile" xsi:type="string">var/log/module.log</argument>
</arguments>
</type>
<!-- etc/adminhtml/di.xml (admin only) -->
<type name="Vendor\Module\Service\Logger">
<arguments>
<argument name="logLevel" xsi:type="string">debug</argument>
</arguments>
</type>
Result in adminhtml area:
- logLevel =
debug(overridden) - logFile =
var/log/module.log(inherited)
Module load order override:
Later modules can override arguments set by earlier modules:
<!-- Module A: etc/di.xml -->
<type name="Magento\Catalog\Model\ResourceModel\Product">
<arguments>
<argument name="connectionName" xsi:type="string">default</argument>
</arguments>
</type>
<!-- Module B: etc/di.xml (loads after Module A) -->
<type name="Magento\Catalog\Model\ResourceModel\Product">
<arguments>
<argument name="connectionName" xsi:type="string">replica</argument>
</arguments>
</type>
Debugging arguments:
# Check compiled DI configuration
cat var/di/etc/module.xml
# Inspect ObjectManager
$objectManager->get(Processor::class);
Quiz
1. What xsi:type is used to pass a PHP class constant as an argument?
2. How are array arguments merged across global and area-specific di.xml?
3. What happens if a scalar type constructor parameter has no di.xml argument and no default value?
4. How do you make an object dependency optional via di.xml?
Flashcards
Question
What are the available xsi:type values for di.xml arguments?
Click to reveal answer
Answer
string, number, boolean, object, array, const, null
Question
What is the scope precedence for argument overriding?
Click to reveal answer
Answer
webapi_rest > webapi_graphql > adminhtml > frontend > crontab > global
Question
How are array arguments merged across scopes?
Click to reveal answer
Answer
By key, with area-specific values taking precedence
Question
Why can't scalar types be auto-resolved?
Click to reveal answer
Answer
ObjectManager cannot infer literal values without configuration or defaults
Question
What is a common use case for xsi:type="const"?
Click to reveal answer
Answer
Passing PHP class constants as configuration values
Revision Notes
Key Takeaways
- 1. String and number arguments pass literal scalar values to constructors
- 2. Boolean arguments control feature flags; null makes dependencies optional
- 3. Object arguments inject specific classes, interfaces, or virtual types
- 4. Array arguments support nested structures and merge by key across scopes
- 5. Const arguments reference PHP class constants
- 6. Area-specific di.xml overrides global arguments for the same key
Interview Tips
- • Explain why scalar types need explicit di.xml configuration
- • Describe how to make an object dependency optional
- • Show examples of nested array arguments
- • Discuss argument merging behavior across scopes
Cheat Sheet
di.xml Arguments Cheat Sheet
Types:
xsi:type="string"→ PHP stringxsi:type="number"→ PHP int/floatxsi:type="boolean"→ PHP boolxsi:type="object"→ PHP class instancexsi:type="array"→ PHP array (mergeable)xsi:type="const"→ PHP constant valuexsi:type="null"→ PHP null
Scope Precedence:
webapi_rest > webapi_graphql > adminhtml > frontend > crontab > global
Array merge rule: Merge by key, later scope wins on conflicts