Generated Code Overview
Magento 2 generates PHP classes to optimize runtime performance. Instead of using the ObjectManager directly, generated classes provide type-safe, cached dependency resolution.
Generated directory structure:
generated/
├── code/
│ ├── Magento/
│ │ └── Catalog/
│ │ └── Model/
│ │ ├── ProductFactory.php
│ │ └── Product\Interceptor.php
│ └── Vendor/
│ └── Module/
│ └── Proxy/
│ └── SomeServiceProxy.php
└── metadata/
├── global.php # Compiled global DI
├── frontend.php # Compiled frontend DI
├── adminhtml.php # Compiled admin DI
└── crontab.php # Compiled cron DI
Types of generated code:
- Factories - Create instances of any injectable class
- Proxies - Lazy-load dependencies on first method call
- Interceptors - Wrap classes with plugin (before/after/around) methods
- Metadata - Compiled DI configuration for fast loading
When code is generated:
# Production mode - compile before deployment
php bin/magento setup:di:compile
# Developer mode - auto-generated on demand
php bin/magento deploy:mode:set developer
Generated code should never be edited manually. It is recreated by the compilation process.
Factory Classes
Factories are generated for every injectable class and provide a type-safe way to create new instances.
Original class:
<?php
namespace Vendor\Module\Model;
class Item
{
public function __construct(
\Magento\Framework\DataObject\Factory $objectFactory,
\Psr\Log\LoggerInterface $logger
) {
// Constructor injection
}
}
Generated factory:
<?php
namespace Vendor\Module\Model\ItemFactory;
// Auto-generated - do not edit
class Factory
{
private $objectManager;
private $instanceName = 'Vendor\\Module\\Model\\Item';
public function __construct(
\Magento\Framework\ObjectManager\ObjectManager $objectManager
) {
$this->objectManager = $objectManager;
}
public function create(array $data = [])
{
return $this->objectManager->create(
$this->instanceName,
$data
);
}
}
Using factories:
public function __construct(
\Vendor\Module\Model\ItemFactory $itemFactory
) {
$this->itemFactory = $itemFactory;
}
public function createNewItem()
{
$item = $this->itemFactory->create();
$item->setName('New Item');
$item->setStatus(1);
return $item;
}
Factories are preferred over ObjectManager::create() because they provide IDE autocompletion, type safety, and follow Magento's coding standards.
Proxy Classes
Proxies wrap a class and defer its instantiation until the first method is called. This improves performance for classes with expensive dependencies.
When to use proxies:
- Class has many dependencies but only one is used rarely
- Dependency involves network calls or file I/O
- Loading the dependency on every request is wasteful
Configure proxy via di.xml:
<config>
<type name="Vendor\Module\Model\Importer">
<arguments>
<argument name="feedParser" xsi:type="object">
Vendor\Module\Model\FeedParser\Proxy
</argument>
</arguments>
</type>
</config>
Generated proxy class (simplified):
<?php
namespace Vendor\Module\Model\FeedParser;
class Proxy implements \Vendor\Module\Model\FeedParserInterface
{
private $objectManager;
private $instanceName = 'Vendor\\Module\\Model\\FeedParser';
private $shared = false;
private $instance;
public function __construct(
\Magento\Framework\ObjectManager\ObjectManager $objectManager,
string $instanceName = '',
bool $shared = false
) {
$this->objectManager = $objectManager;
$this->instanceName = $instanceName ?: $this->instanceName;
$this->shared = $shared;
}
private function loadInstance()
{
if ($this->instance === null) {
$this->instance = $this->objectManager->create(
$this->instanceName
);
}
return $this->instance;
}
public function parse($url)
{
return $this->loadInstance()->parse($url);
}
}
Proxy naming convention: {ClassName}\Proxy or {Namespace}\{ClassName}\Proxy
Interceptors (Plugin System)
Interceptors are generated wrapper classes that enable the plugin system. They call before, after, and around methods defined in plugin configuration.
Plugin configuration:
<config>
<type name="Magento\Catalog\Model\ProductRepository">
<plugin name="vendor_after_save"
type="Vendor\Module\Plugin\ProductAfterSave"
sortOrder="10"/>
</type>
</config>
Plugin class:
<?php
namespace Vendor\Module\Plugin;
class ProductAfterSave
{
public function afterSave(
\Magento\Catalog\Model\ProductRepository $subject,
$result
) {
// Code after save
$this->logger->info('Product saved: ' . $result->getSku());
return $result;
}
public function beforeSave(
\Magento\Catalog\Model\ProductRepository $subject,
$product
) {
// Code before save
$product->setData('custom_field', 'value');
return [$product];
}
}
Generated interceptor (simplified):
<?php
namespace Magento\Catalog\Model;
class ProductRepository\Interceptor extends ProductRepository
{
private $pluginManager;
public function save($product)
{
// Before plugins
$pluginResult = $this->pluginManager->call(
$this,
'beforeSave',
[$product]
);
if (!empty($pluginResult)) {
$product = $pluginResult[0];
}
// Execute original method
$result = parent::save($product);
// After plugins
$result = $this->pluginManager->call(
$this,
'afterSave',
[$result]
);
return $result;
}
}
Regenerate interceptors:
php bin/magento setup:di:compile
# or in developer mode, they regenerate automatically
Quiz
1. When would you use a Proxy instead of direct instantiation?
2. What command generates all Magento code artifacts?
Flashcards
Question
What suffix do generated factory classes have?
Click to reveal answer
Answer
Factory (e.g., ProductFactory)
Question
What suffix do generated proxy classes have?
Click to reveal answer
Answer
Proxy (e.g., SomeClass\Proxy)
Question
What do interceptors wrap?
Click to reveal answer
Answer
Original class methods to enable plugin before/after/around execution
Question
Where is compiled DI metadata stored?
Click to reveal answer
Answer
generated/metadata/{area}.php
Revision Notes
Key Takeaways
- 1. Magento generates factories, proxies, interceptors, and metadata
- 2. Factories create new instances of injectable classes
- 3. Proxies defer expensive dependencies until first use
- 4. Interceptors enable the plugin system (before/after/around)
- 5. All generated code goes in the generated/ directory
- 6. Run setup:di:compile to regenerate all code
Interview Tips
- • Explain the three types of generated code and their purposes
- • Describe when you would configure a proxy
- • Discuss how interceptors enable the plugin system
- • Know the difference between developer and production mode code generation
- • Explain why ObjectManager direct usage is discouraged
Cheat Sheet
Generated Code Cheat Sheet
Output Dir: generated/
Compile: php bin/magento setup:di:compile
Types:
- Factory (
{Class}Factory) - Creates new instances - Proxy (
{Class}\Proxy) - Lazy-loads dependencies - Interceptor (
{Class}\Interceptor) - Plugin wrapper
Metadata: generated/metadata/{area}.php
di.xml Proxy Config:
<argument xsi:type="object">ClassName\Proxy</argument>
Mode Behavior:
- Developer: Auto-regenerate
- Production: Pre-compile required