Virtual Type Fundamentals
What is a Virtual Type?
A virtual type creates an anonymous class configuration without defining a new PHP class. It's a DI alias with custom arguments.
<virtualType name="ActiveWarrantyRepository" type="Amazon\Prep\Model\WarrantyRepository">
<arguments>
<argument name="statusFilter" xsi:type="string">active</argument>
</arguments>
</virtualType>
How Virtual Types Work
1. Virtual type is registered as a named configuration
2. When injected, ObjectManager creates the type class
3. Arguments are applied from the virtual type config
4. Instance is created (shared or non-shared based on config)
Basic Virtual Type
<!-- Define virtual type -->
<virtualType name="PremiumWarranty" type="Amazon\Prep\Model\Warranty">
<arguments>
<argument name="type" xsi:type="string">premium</argument>
<argument name="duration" xsi:type="number">36</argument>
</arguments>
</virtualType>
<!-- Use virtual type in other configuration -->
<type name="Amazon\Prep\Service\WarrantyService">
<arguments>
<argument name="defaultWarranty" xsi:type="object">PremiumWarranty</argument>
</arguments>
</type>
Virtual Type vs Preference
| Aspect | Virtual Type | Preference |
|---|---|---|
| Purpose | Create named configuration | Replace interface implementation |
| New class | No (uses existing) | No (maps to existing) |
| Customization | Arguments only | Full replacement |
| Conflict | Low | High |
| Use case | Configuration aliasing | Interface replacement |
Virtual Type Configuration
Virtual Type with Arguments
<virtualType name="CachedProductRepository" type="Magento\Catalog\Model\ProductRepository">
<arguments>
<argument name="cache" xsi:type="object">Magento\Framework\Cache\Frontend\Interface</argument>
<argument name="cacheLifetime" xsi:type="number">3600</argument>
<argument name="cacheTags" xsi:type="array">
<item name="0" xsi:type="string">catalog_product</item>
</argument>
</arguments>
</virtualType>
Virtual Type with Shared Flag
<!-- Non-shared virtual type -->
<virtualType name="TransientWarranty" type="Amazon\Prep\Model\Warranty" shared="false"/>
<!-- Shared virtual type (default) -->
<virtualType name="SingletonWarranty" type="Amazon\Prep\Model\Warranty"/>
Virtual Type for Collections
<virtualType name="ActiveWarrantyCollection" type="Amazon\Prep\Model\ResourceModel\Warranty\Collection">
<arguments>
<argument name="mainTable" xsi:type="string">vendor_warranty</argument>
<argument name="idFieldName" xsi:type="string">warranty_id</argument>
</arguments>
</virtualType>
<!-- Use in repository -->
<type name="Amazon\Prep\Model\WarrantyRepository">
<arguments>
<argument name="collectionFactory" xsi:type="object">ActiveWarrantyCollection</argument>
</arguments>
</type>
Virtual Type for Helpers
<virtualType name="StoreConfigHelper" type="Amazon\Prep\Helper\Config">
<arguments>
<argument name="configPath" xsi:type="string">vendor_prep/general</argument>
<argument name="scope" xsi:type="string">store</argument>
</arguments>
</virtualType>
Virtual Type Use Cases
Use Case 1: Different Configurations for Same Class
<!-- Standard warranty -->
<virtualType name="StandardWarranty" type="Amazon\Prep\Model\Warranty">
<arguments>
<argument name="duration" xsi:type="number">12</argument>
<argument name="price" xsi:type="number">49.99</argument>
</arguments>
</virtualType>
<!-- Premium warranty -->
<virtualType name="PremiumWarranty" type="Amazon\Prep\Model\Warranty">
<arguments>
<argument name="duration" xsi:type="number">36</argument>
<argument name="price" xsi:type="number">149.99</argument>
</arguments>
</virtualType>
<!-- Use in services -->
<type name="Amazon\Prep\Service\WarrantyService">
<arguments>
<argument name="standardWarranty" xsi:type="object">StandardWarranty</argument>
<argument name="premiumWarranty" xsi:type="object">PremiumWarranty</argument>
</arguments>
</type>
Use Case 2: Testing
<!-- etc/di.xml (test area) -->
<virtualType name="MockWarrantyRepository" type="Amazon\Prep\Model\Mock\MockWarrantyRepository">
<arguments>
<argument name="testData" xsi:type="array">
<item name="0" xsi:type="array">
<item name="id" xsi:type="number">1</item>
<item name="name" xsi:type="string">Test Warranty</item>
</item>
</argument>
</arguments>
</virtualType>
<type name="Amazon\Prep\Service\WarrantyService">
<arguments>
<argument name="repository" xsi:type="object">MockWarrantyRepository</argument>
</arguments>
</type>
Use Case 3: Environment-Specific
<!-- etc/di.xml (global) -->
<virtualType name="DatabaseLogger" type="Amazon\Prep\Logger\Database">
<arguments>
<argument name="table" xsi:type="string">logs</argument>
</arguments>
</virtualType>
<!-- etc/frontend/di.xml -->
<virtualType name="FileLogger" type="Amazon\Prep\Logger\File">
<arguments>
<argument name="path" xsi:type="string">var/log/frontend.log</argument>
</arguments>
</virtualType>
Virtual Type Best Practices
Naming Conventions
<!-- Use descriptive names -->
<virtualType name="ActiveWarrantyRepository" .../> <!-- Good -->
<virtualType name="VType1" .../> <!-- Bad -->
<!-- Prefix with module name -->
<virtualType name="AmazonPrepActiveWarranty" .../> <!-- Good -->
<virtualType name="ActiveWarranty" .../> <!-- Okay if unique -->
When to Use Virtual Types
✅ Use when:
- Different configurations for same class
- Creating named aliases for clarity
- Testing with mock implementations
- Environment-specific configurations
- Avoiding preference conflicts
⌠Don't use when:
- You need to replace entire class (use preference)
- You need to extend behavior (use plugin)
- Simple argument override (use type arguments directly)
Debugging Virtual Types
# Check generated code
cat var/di/development.log | grep -A10 "ActiveWarrantyRepository"
# Verify virtual type resolution
bin/magento setup:di:compile
# Check for errors
bin/magento dev:di:log
Virtual Type + Plugin Combo
<!-- Virtual type for configuration -->
<virtualType name="ConfiguredService" type="Amazon\Prep\Service\WarrantyService">
<arguments>
<argument name="apiKey" xsi:type="string">sk_test_abc</argument>
</arguments>
</virtualType>
<!-- Plugin extends the virtual type -->
<type name="Amazon\Prep\Service\WarrantyService">
<plugin name="service_logging" type="Amazon\Prep\Plugin\ServicePlugin"/>
</type>
Quiz
1. What is a virtual type in Magento DI?
2. When should you use a virtual type instead of a preference?
3. How do you use a virtual type in other configurations?
Flashcards
Question
What does a virtual type create?
Click to reveal answer
Answer
An anonymous class configuration with custom arguments
Question
How do you reference a virtual type?
Click to reveal answer
Answer
xsi:type="object" with the virtual type name
Question
Virtual type vs preference: which replaces entire class?
Click to reveal answer
Answer
Preference replaces entire class; virtual type configures existing class
Question
When are virtual types useful for testing?
Click to reveal answer
Answer
When you need mock implementations with test data
Question
Can virtual types be non-shared?
Click to reveal answer
Answer
Yes, set shared="false" on the virtualType element
Revision Notes
Key Takeaways
- 1. Virtual types create named configurations for existing classes
- 2. Use xsi:type="object" to reference virtual types
- 3. Virtual types are for configuration; preferences are for replacement
- 4. Virtual types are useful for testing and environment-specific configs
- 5. Always use descriptive naming conventions for virtual types
Interview Tips
- • Explain virtual types vs preferences vs plugins
- • Know when to use virtual types for testing
- • Be ready to create virtual type configurations
- • Discuss virtual type naming best practices
Cheat Sheet
Virtual type:
<virtualType name="Alias" type="RealClass">
<arguments>
<argument name="key" xsi:type="string">value</argument>
</arguments>
</virtualType>
Reference:
<argument name="dep" xsi:type="object">Alias</argument>
Use cases: config aliasing, testing, environment-specific